static int set_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *sw_params, snd_spcm_xrun_type_t xrun_type) { int err; err = snd_pcm_sw_params_current(pcm, sw_params); if (err < 0) return err; err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size); if (err < 0) return err; err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size); if (err < 0) return err; switch (xrun_type) { case SND_SPCM_XRUN_STOP: err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size); break; case SND_SPCM_XRUN_IGNORE: err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary); break; default: return -EINVAL; } if (err < 0) return err; err = snd_pcm_sw_params_set_xfer_align(pcm, sw_params, 1); if (err < 0) return err; err = snd_pcm_sw_params(pcm, sw_params); if (err < 0) return err; return 0; }
static void set_params(void) { hwparams.format=SND_PCM_FORMAT_S16_LE; hwparams.channels=2; hwparams.rate=44100; snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_format(handle, params, hwparams.format); snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); buffer_time=0; snd_pcm_hw_params_get_buffer_time_max(params,&buffer_time, 0); period_time=125000; snd_pcm_hw_params_set_period_time_near(handle, params,&period_time, 0); buffer_time = 500000; snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); /*monotonic = */snd_pcm_hw_params_is_monotonic(params); /*can_pause = */snd_pcm_hw_params_can_pause(params); printf("sizeof(params) : %d\n",sizeof(params)); snd_pcm_hw_params(handle, params); snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); size_t n=chunk_size; snd_pcm_sw_params_set_avail_min(handle, swparams, n); snd_pcm_uframes_t start_threshold, stop_threshold; start_threshold=22050; snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); stop_threshold=22050; snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); snd_pcm_format_physical_width(hwparams.format); }
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period, int nperiods) { int err; /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err)); return err; } /* start the transfer when the buffer is full */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 ); if (err < 0) { printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err)); return err; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, 1 ); if (err < 0) { printf("Unable to set avail min for capture: %s\n", snd_strerror(err)); return err; } /* align all transfers to 1 sample */ err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1); if (err < 0) { printf("Unable to set transfer align for capture: %s\n", snd_strerror(err)); return err; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for capture: %s\n", snd_strerror(err)); return err; } return 0; }
bool AudioInputALSA::PrepSwParams(void) { snd_pcm_sw_params_t* swparams; snd_pcm_sw_params_alloca(&swparams); snd_pcm_uframes_t boundary; if (AlsaBad(snd_pcm_sw_params_current(pcm_handle, swparams), "failed to get swparams")) return false; if (AlsaBad(snd_pcm_sw_params_get_boundary(swparams, &boundary), "failed to get boundary")) return false; // explicit start, not auto start if (AlsaBad(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, boundary), "failed to set start threshold")) return false; if (AlsaBad(snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, boundary), "failed to set stop threshold")) return false; if (AlsaBad(snd_pcm_sw_params(pcm_handle, swparams), "failed to set software parameters")) return false; return true; }
static int ao_alsa_init(dtaudio_output_t *aout, dtaudio_para_t *para) { memcpy(&wrapper->para, para, sizeof(dtaudio_para_t)); snd_pcm_t *alsa_handle; snd_pcm_hw_params_t *alsa_hwparams; snd_pcm_sw_params_t *alsa_swparams; snd_pcm_uframes_t size; snd_pcm_uframes_t boundary; alsa_ctx_t *ctx = (alsa_ctx_t *)malloc(sizeof(*ctx)); if (!ctx) { return -1; } wrapper->ao_priv = ctx; int afmt = format_to_alsa(wrapper->para.bps); uint32_t channels = wrapper->para.dst_channels; uint32_t sr = wrapper->para.dst_samplerate; int bytes_per_sample = snd_pcm_format_physical_width(afmt) * channels / 8; int err = 0; err = snd_pcm_open(&alsa_handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); free(ctx); wrapper->ao_priv = NULL; return -1; } snd_pcm_hw_params_alloca(&alsa_hwparams); snd_pcm_sw_params_alloca(&alsa_swparams); err = snd_pcm_hw_params_any(alsa_handle, alsa_hwparams); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_access(alsa_handle, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_format(alsa_handle, alsa_hwparams, afmt); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_channels_near(alsa_handle, alsa_hwparams, &channels); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_hwparams, &sr, NULL); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_hw_params(alsa_handle, alsa_hwparams); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } /****************************************************************** * Set HW Params Finish ******************************************************************/ /* buffer size means the entire size of alsa pcm buffer size*/ err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &size); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } ctx->buf_size = size * bytes_per_sample; /*period size means count processed every interrupt*/ err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &size, NULL); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } ctx->trunk_size = size * bytes_per_sample; dt_info(TAG, "outburst: %d, bytes_per_sample: %d, buffersize: %d\n", ctx->trunk_size, bytes_per_sample, ctx->buf_size); /****************************************************************** * set sw params ******************************************************************/ err = snd_pcm_sw_params_current(alsa_handle, alsa_swparams); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } #if SND_LIB_VERSION >= 0x000901 err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary); #else boundary = 0x7fffffff; #endif err = snd_pcm_sw_params_set_start_threshold(alsa_handle, alsa_swparams, size); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } err = snd_pcm_sw_params_set_stop_threshold(alsa_handle, alsa_swparams, boundary); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } #if SND_LIB_VERSION >= 0x000901 err = snd_pcm_sw_params_set_silence_size(alsa_handle, alsa_swparams, boundary); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } #endif err = snd_pcm_sw_params(alsa_handle, alsa_swparams); if (err < 0) { dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err)); return -1; } ctx->pause_support = snd_pcm_hw_params_can_pause(alsa_hwparams); //buf size limit ctx->buf_threshold = bytes_per_sample * sr * DEFAULT_TIME_SIZE / 1000; dt_info(TAG, "alsa audio init ok! outburst:%d thres:%d \n", ctx->trunk_size, ctx->buf_threshold); ctx->handle = alsa_handle; ctx->channels = wrapper->para.dst_channels; ctx->bps = wrapper->para.bps; ctx->samplerate = wrapper->para.dst_samplerate; return 0; }
static void set_params(void) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; int err; size_t n; unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { error("Broken configuration for this PCM: no configurations available"); exit(EXIT_FAILURE); } if (mmap_flag) { snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); snd_pcm_access_mask_none(mask); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = snd_pcm_hw_params_set_access_mask(handle, params, mask); } else if (interleaved) err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); else err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED); if (err < 0) { error("Access type not available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); if (err < 0) { error("Sample format non available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); if (err < 0) { error("Channels count non available"); exit(EXIT_FAILURE); } #if 0 err = snd_pcm_hw_params_set_periods_min(handle, params, 2); assert(err >= 0); #endif rate = hwparams.rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); assert(err >= 0); if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) { if (!quiet_mode) { char plugex[64]; const char *pcmname = snd_pcm_name(handle); fprintf(stderr, "Warning: rate is not accurate (requested = %iHz, got = %iHz)\n", rate, hwparams.rate); if (! pcmname || strchr(snd_pcm_name(handle), ':')) *plugex = 0; else snprintf(plugex, sizeof(plugex), "(-Dplug:%s)", snd_pcm_name(handle)); fprintf(stderr, " please, try the plug plugin %s\n", plugex); } } rate = hwparams.rate; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; } if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0); assert(err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames); } assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { error("Unable to install hw params:"); snd_pcm_hw_params_dump(params, log); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); if (chunk_size == buffer_size) { error("Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); if (avail_min < 0) n = chunk_size; else n = (double) rate * avail_min / 1000000; err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); if (err < 0) { error("Setting sw params failed\n"); } /* round up to closest transfer boundary */ n = buffer_size; if (start_delay <= 0) { start_threshold = n + (double) rate * start_delay / 1000000; } else start_threshold = (double) rate * start_delay / 1000000; if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); if (stop_delay <= 0) stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; else stop_threshold = (double) rate * stop_delay / 1000000; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { error("unable to install sw params:"); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } if (verbose) snd_pcm_dump(handle, log); bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_frame = bits_per_sample * hwparams.channels; chunk_bytes = chunk_size * bits_per_frame / 8; audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { error("not enough memory"); exit(EXIT_FAILURE); } // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); /* stereo VU-meter isn't always available... */ if (vumeter == VUMETER_STEREO) { if (hwparams.channels != 2 || !interleaved || verbose > 2) vumeter = VUMETER_MONO; } /* show mmap buffer arragment */ if (mmap_flag && verbose) { const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t offset; int i; err = snd_pcm_mmap_begin(handle, &areas, &offset, &chunk_size); if (err < 0) { error("snd_pcm_mmap_begin problem: %s", snd_strerror(err)); exit(EXIT_FAILURE); } for (i = 0; i < hwparams.channels; i++) fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(hwparams.format)); /* not required, but for sure */ snd_pcm_mmap_commit(handle, offset, 0); } buffer_frames = buffer_size; /* for position test */ }
bool open() { // Open the Alsa playback device. int err=-1,count=0; unsigned int freakuency = frequency; while((count < 5) && (err < 0)) { err = snd_pcm_open ( &handle, ALSA_OUTPUT_NAME, SND_PCM_STREAM_PLAYBACK, 0 ); if(err < 0) { count++; qWarning()<<"QAudioOutput::open() err="<<err<<", count="<<count; } } if (( err < 0)||(handle == 0)) { qWarning( "QAudioOuput: snd_pcm_open: error %d", err ); return false; } snd_pcm_nonblock( handle, 0 ); // Set the desired HW parameters. snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca( &hwparams ); err = snd_pcm_hw_params_any( handle, hwparams ); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_any: err %d", err); return false; } err = snd_pcm_hw_params_set_access( handle, hwparams, access ); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_access: err %d", err); return false; } err = snd_pcm_hw_params_set_format( handle, hwparams, ( bitsPerSample == 16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8 ) ); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_format: err %d", err); return false; } err = snd_pcm_hw_params_set_channels ( handle, hwparams, (unsigned int)channels ); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_channels: err %d", err); return false; } err = snd_pcm_hw_params_set_rate_near ( handle, hwparams, &freakuency, 0 ); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_rate_near: err %d", err); return false; } #ifndef ALSA_BUFFER_SIZE err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_get_buffer_size: err %d",err); } #else buffer_size = ALSA_BUFFER_SIZE; err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } #endif #ifndef ALSA_PERIOD_SIZE period_time = buffer_time/4; err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_time_near: err %d",err); } #else period_size = ALSA_PERIOD_SIZE; err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, 0); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params_set_period_size_near: err %d",err); } #endif err = snd_pcm_hw_params(handle, hwparams); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_hw_params: err %d", err); return false; } int dir; unsigned int vval, vval2; snd_pcm_access_t val; snd_pcm_format_t fval; snd_pcm_subformat_t sval; qLog(QAudioOutput) << "PCM handle name =" << snd_pcm_name(handle); qLog(QAudioOutput) << "PCM state =" << snd_pcm_state_name(snd_pcm_state(handle)); snd_pcm_hw_params_get_access(hwparams,&val); vval = (unsigned int)val; if ( (int)vval != (int)access ) { qWarning( "QAudioInput: access type not set, want %s got %s", snd_pcm_access_name((snd_pcm_access_t)access), snd_pcm_access_name((snd_pcm_access_t)vval) ); access = (snd_pcm_access_t)vval; } qLog(QAudioOutput) << "access type =" << snd_pcm_access_name((snd_pcm_access_t)vval); snd_pcm_hw_params_get_format(hwparams, &fval); vval = (unsigned int)fval; if ( (int)vval != (int)format ) { qWarning( "QAudioInput: format type not set, want %s got %s", snd_pcm_format_name((snd_pcm_format_t)format), snd_pcm_format_name((snd_pcm_format_t)vval) ); format = (snd_pcm_format_t)vval; } qLog(QAudioOutput) << QString("format = '%1' (%2)").arg(snd_pcm_format_name((snd_pcm_format_t)vval)) .arg(snd_pcm_format_description((snd_pcm_format_t)vval)) .toLatin1().constData(); snd_pcm_hw_params_get_subformat(hwparams,&sval); vval = (unsigned int)sval; qLog(QAudioOutput) << QString("subformat = '%1' (%2)").arg(snd_pcm_subformat_name((snd_pcm_subformat_t)vval)) .arg(snd_pcm_subformat_description((snd_pcm_subformat_t)vval)) .toLatin1().constData(); snd_pcm_hw_params_get_channels(hwparams, &vval); if ( (int)vval != (int)channels ) { qWarning( "QAudioInput: channels type not set, want %d got %d",channels,vval); channels = vval; } qLog(QAudioOutput) << "channels =" << vval; snd_pcm_hw_params_get_rate(hwparams, &vval, &dir); if ( (int)vval != (int)frequency ) { qWarning( "QAudioInput: frequency type not set, want %d got %d",frequency,vval); frequency = vval; } qLog(QAudioOutput) << "rate =" << vval << "bps"; snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); qLog(QAudioOutput) << "period time =" << period_time << "us"; snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir); qLog(QAudioOutput) << "period size =" << (int)period_size << "frames"; qLog(QAudioOutput) << "buffer time =" << (int)buffer_time << "us"; qLog(QAudioOutput) << "buffer size =" << (int)buffer_size << "frames"; snd_pcm_hw_params_get_periods(hwparams, &vval, &dir); periods = vval; qLog(QAudioOutput) << "periods per buffer =" << vval << "frames"; snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2); qLog(QAudioOutput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData(); vval = snd_pcm_hw_params_get_sbits(hwparams); qLog(QAudioOutput) << "significant bits =" << vval; vval = snd_pcm_hw_params_is_batch(hwparams); qLog(QAudioOutput) << "is batch =" << vval; vval = snd_pcm_hw_params_is_block_transfer(hwparams); qLog(QAudioOutput) << "is block transfer =" << vval; vval = snd_pcm_hw_params_is_double(hwparams); qLog(QAudioOutput) << "is double =" << vval; vval = snd_pcm_hw_params_is_half_duplex(hwparams); qLog(QAudioOutput) << "is half duplex =" << vval; vval = snd_pcm_hw_params_is_joint_duplex(hwparams); qLog(QAudioOutput) << "is joint duplex =" << vval; vval = snd_pcm_hw_params_can_overrange(hwparams); qLog(QAudioOutput) << "can overrange =" << vval; vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams); qLog(QAudioOutput) << "can mmap =" << vval; vval = snd_pcm_hw_params_can_pause(hwparams); qLog(QAudioOutput) << "can pause =" << vval; vval = snd_pcm_hw_params_can_resume(hwparams); qLog(QAudioOutput) << "can resume =" << vval; vval = snd_pcm_hw_params_can_sync_start(hwparams); qLog(QAudioOutput) << "can sync start =" << vval; // Set the desired SW parameters. snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_sw_params_current(handle, swparams); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_sw_params_current: err %d",err); } err = snd_pcm_sw_params_set_start_threshold(handle,swparams,buffer_size); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_sw_params_set_start_threshold: err %d",err); } err = snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_size); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_sw_params_set_stop_threshold: err %d",err); } err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_sw_params_set_avail_min: err %d",err); } err = snd_pcm_sw_params(handle, swparams); if ( err < 0 ) { qWarning( "QAudioOutput: snd_pcm_sw_params: err %d",err); } // Prepare for audio output. snd_pcm_prepare( handle ); return true; }
static void set_params(void) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; int err; size_t n; snd_pcm_uframes_t xfer_align; unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { error(_("Broken configuration for this PCM: no configurations available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { error(_("Access type not available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); if (err < 0) { error(_("Sample format non available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); if (err < 0) { error(_("Channels count non available")); exit(EXIT_FAILURE); } #if 0 err = snd_pcm_hw_params_set_periods_min(handle, params, 2); assert(err >= 0); #endif rate = hwparams.rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); assert(err >= 0); if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) { if (!quiet_mode) { char plugex[64]; const char *pcmname = snd_pcm_name(handle); fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate); if (! pcmname || strchr(snd_pcm_name(handle), ':')) *plugex = 0; else snprintf(plugex, sizeof(plugex), "(-Dplug:%s)", snd_pcm_name(handle)); fprintf(stderr, _(" please, try the plug plugin %s\n"), plugex); } } rate = hwparams.rate; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; } if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0); assert(err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames); } assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { error(_("Unable to install hw params:")); snd_pcm_hw_params_dump(params, log); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); if (chunk_size == buffer_size) { error(_("Can't use period equal to buffer size (%lu == %lu)"), chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align); if (err < 0) { error(_("Unable to obtain xfer align\n")); exit(EXIT_FAILURE); } if (sleep_min) xfer_align = 1; err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min); assert(err >= 0); if (avail_min < 0) n = chunk_size; else n = (double) rate * avail_min / 1000000; err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); // round up to closest transfer boundary n = (buffer_size / xfer_align) * xfer_align; start_threshold = n; if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); stop_threshold = buffer_size; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err >= 0); err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { error(_("unable to install sw params:")); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_frame = bits_per_sample * hwparams.channels; chunk_bytes = chunk_size * bits_per_frame / 8; audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { error(_("not enough memory")); exit(EXIT_FAILURE); } // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); }
int ai_alsa_setup(audio_in_t *ai) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; int buffer_size; int err; unsigned int rate; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(ai->alsa.handle, params); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig); return -1; } err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType); return -1; } err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt); return -1; } err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); if (err < 0) { ai->channels = snd_pcm_hw_params_get_channels(params); mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount, ai->channels); } else { ai->channels = ai->req_channels; } err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0); assert(err >= 0); rate = err; ai->samplerate = rate; ai->alsa.buffer_time = 1000000; ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, ai->alsa.buffer_time, 0); assert(ai->alsa.buffer_time >= 0); ai->alsa.period_time = ai->alsa.buffer_time / 4; ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, ai->alsa.period_time, 0); assert(ai->alsa.period_time >= 0); err = snd_pcm_hw_params(ai->alsa.handle, params); if (err < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams); snd_pcm_hw_params_dump(params, ai->alsa.log); return -1; } ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0); buffer_size = snd_pcm_hw_params_get_buffer_size(params); if (ai->alsa.chunk_size == buffer_size) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size); return -1; } snd_pcm_sw_params_current(ai->alsa.handle, swparams); err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0); assert(err >= 0); err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); assert(err >= 0); err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); assert(err >= 0); err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); assert(err >= 0); assert(err >= 0); if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams); snd_pcm_sw_params_dump(swparams, ai->alsa.log); return -1; } if (mp_msg_test(MSGT_TV, MSGL_V)) { snd_pcm_dump(ai->alsa.handle, ai->alsa.log); } ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; ai->samplesize = ai->alsa.bits_per_sample; ai->bytes_per_sample = ai->alsa.bits_per_sample/8; return 0; }
int main(int argc, char *argv[]) { const char *dev; int r, cap, count = 0; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; snd_pcm_t *pcm; unsigned rate = 44100; unsigned periods = 2; snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */ int dir = 1; struct timespec start, last_timestamp = { 0, 0 }; uint64_t start_us, last_us = 0; snd_pcm_sframes_t last_avail = 0, last_delay = 0; struct pollfd *pollfds; int n_pollfd; int64_t sample_count = 0; struct sched_param sp; r = -1; #ifdef _POSIX_PRIORITY_SCHEDULING sp.sched_priority = 5; r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp); #endif if (r) printf("Could not get RT prio. :(\n"); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); snd_pcm_status_alloca(&status); r = clock_gettime(CLOCK_MONOTONIC, &start); assert(r == 0); start_us = timespec_us(&start); dev = argc > 1 ? argv[1] : "front:AudioPCI"; cap = argc > 2 ? atoi(argv[2]) : 0; if (cap == 0) r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0); else r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0); assert(r == 0); r = snd_pcm_hw_params_any(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0); assert(r == 0); r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); assert(r == 0); r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE); assert(r == 0); r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL); assert(r == 0); r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2); assert(r == 0); r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir); assert(r == 0); r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size); assert(r == 0); r = snd_pcm_hw_params(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_current(pcm, hwparams); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); if (cap == 0) r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1); else r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0); assert(r == 0); r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0); assert(r == 0); r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); assert(r == 0); r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size); assert(r == 0); r = snd_pcm_sw_params_get_boundary(swparams, &boundary); assert(r == 0); r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary); assert(r == 0); r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE); assert(r == 0); r = snd_pcm_sw_params(pcm, swparams); assert(r == 0); r = snd_pcm_prepare(pcm); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */ n_pollfd = snd_pcm_poll_descriptors_count(pcm); assert(n_pollfd > 0); pollfds = malloc(sizeof(struct pollfd) * n_pollfd); assert(pollfds); r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd); assert(r == n_pollfd); printf("Starting. Buffer size is %u frames\n", (unsigned int) buffer_size); if (cap) { r = snd_pcm_start(pcm); assert(r == 0); } for (;;) { snd_pcm_sframes_t avail, delay; struct timespec now, timestamp; unsigned short revents; int handled = 0; uint64_t now_us, timestamp_us; snd_pcm_state_t state; unsigned long long pos; r = poll(pollfds, n_pollfd, 0); assert(r >= 0); r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents); assert(r == 0); if (cap == 0) assert((revents & ~POLLOUT) == 0); else assert((revents & ~POLLIN) == 0); avail = snd_pcm_avail(pcm); assert(avail >= 0); r = snd_pcm_status(pcm, status); assert(r == 0); /* This assertion fails from time to time. ALSA seems to be broken */ /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */ /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */ snd_pcm_status_get_htstamp(status, ×tamp); delay = snd_pcm_status_get_delay(status); state = snd_pcm_status_get_state(status); r = clock_gettime(CLOCK_MONOTONIC, &now); assert(r == 0); assert(!revents || avail > 0); if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) { snd_pcm_sframes_t sframes; static const uint16_t psamples[2] = { 0, 0 }; uint16_t csamples[2]; if (cap == 0) sframes = snd_pcm_writei(pcm, psamples, 1); else sframes = snd_pcm_readi(pcm, csamples, 1); assert(sframes == 1); handled = 1; sample_count++; } if (!handled && memcmp(×tamp, &last_timestamp, sizeof(timestamp)) == 0 && avail == last_avail && delay == last_delay) { /* This is boring */ continue; } now_us = timespec_us(&now); timestamp_us = timespec_us(×tamp); if (cap == 0) pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100); else pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100); if (count++ % 50 == 0) printf("Elapsed\tCPU\tALSA\tPos\tSamples\tavail\tdelay\trevents\thandled\tstate\n"); printf("%llu\t%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n", (unsigned long long) (now_us - last_us), (unsigned long long) (now_us - start_us), (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0), pos, (unsigned long long) sample_count, (signed long) avail, (signed long) delay, revents, handled, state); if (cap == 0) /** When this assert is hit, most likely something bad * happened, i.e. the avail jumped suddenly. */ assert((unsigned) avail <= buffer_size); last_avail = avail; last_delay = delay; last_timestamp = timestamp; last_us = now_us; } return 0; }
int ga_alsa_set_param(struct Xcap_alsa_param *param) { snd_pcm_hw_params_t *hwparams = NULL; snd_pcm_sw_params_t *swparams = NULL; size_t bits_per_sample; unsigned int rate; unsigned int buffer_time = 500000; // in the unit of microsecond unsigned int period_time = 125000; // = buffer_time/4; int monotonic = 0; snd_pcm_uframes_t start_threshold, stop_threshold; int err; // snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if((err = snd_pcm_hw_params_any(param->handle, hwparams)) < 0) { ga_error("ALSA: set_param - no configurations available\n"); return -1; } if((err = snd_pcm_hw_params_set_access(param->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { ga_error("ALSA: set_param - access type (interleaved) not available\n"); return -1; } if((err = snd_pcm_hw_params_set_format(param->handle, hwparams, param->format)) < 0) { ga_error("ALSA: set_param - unsupported sample format.\n"); return -1; } if((err = snd_pcm_hw_params_set_channels(param->handle, hwparams, param->channels)) < 0) { ga_error("ALSA: set_param - channles count not available\n"); return -1; } rate = param->samplerate; if((err = snd_pcm_hw_params_set_rate_near(param->handle, hwparams, &rate, 0)) < 0) { ga_error("ALSA: set_param - set rate failed.\n"); return -1; } if((double)param->samplerate*1.05 < rate || (double)param->samplerate*0.95 > rate) { ga_error("ALSA: set_param/warning - inaccurate rate (req=%iHz, got=%iHz)\n", param->samplerate, rate); } // period_time = buffer_time/4; if((err = snd_pcm_hw_params_set_period_time_near(param->handle, hwparams, &period_time, 0)) < 0) { ga_error("ALSA: set_param - set period time failed.\n"); return -1; } if((err = snd_pcm_hw_params_set_buffer_time_near(param->handle, hwparams, &buffer_time, 0)) < 0) { ga_error("ALSA: set_param - set buffer time failed.\n"); return -1; } // monotonic = snd_pcm_hw_params_is_monotonic(hwparams); if((err = snd_pcm_hw_params(param->handle, hwparams)) < 0) { ga_error("ALSA: set_param - unable to install hw params:"); snd_pcm_hw_params_dump(hwparams, sndlog); return -1; } snd_pcm_hw_params_get_period_size(hwparams, ¶m->chunk_size, 0); snd_pcm_hw_params_get_buffer_size(hwparams, ¶m->buffer_size); if(param->chunk_size == param->buffer_size) { ga_error("ALSA: set_param - cannot use period equal to buffer size (%lu==%lu)\n", param->chunk_size, param->buffer_size); return -1; } // snd_pcm_sw_params_current(param->handle, swparams); err = snd_pcm_sw_params_set_avail_min(param->handle, swparams, param->chunk_size); // start_delay = 1 for capture start_threshold = (double) param->samplerate * /*start_delay=*/ 1 / 1000000; if(start_threshold < 1) start_threshold = 1; if(start_threshold > param->buffer_size) start_threshold = param->buffer_size; if((err = snd_pcm_sw_params_set_start_threshold(param->handle, swparams, start_threshold)) < 0) { ga_error("ALSA: set_param - set start threshold failed.\n"); return -1; } // stop_delay = 0 stop_threshold = param->buffer_size; if((err = snd_pcm_sw_params_set_stop_threshold(param->handle, swparams, stop_threshold)) < 0) { ga_error("ALSA: set_param - set stop threshold failed.\n"); return -1; } // if(snd_pcm_sw_params(param->handle, swparams) < 0) { ga_error("ALSA: set_param - unable to install sw params:"); snd_pcm_sw_params_dump(swparams, sndlog); return -1; } bits_per_sample = snd_pcm_format_physical_width(param->format); if(param->bits_per_sample != bits_per_sample) { ga_error("ALSA: set_param - BPS/HW configuration mismatched %d != %d)\n", param->bits_per_sample, bits_per_sample); } param->bits_per_frame = param->bits_per_sample * param->channels; param->chunk_bytes = param->chunk_size * param->bits_per_frame / 8; return 0; }
static ALCboolean alsa_reset_playback(ALCdevice *device) { alsa_data *data = (alsa_data*)device->ExtraData; snd_pcm_uframes_t periodSizeInFrames; unsigned int periodLen, bufferLen; snd_pcm_sw_params_t *sp = NULL; snd_pcm_hw_params_t *hp = NULL; snd_pcm_access_t access; snd_pcm_format_t format; unsigned int periods; unsigned int rate; const char *funcerr; int allowmmap; int err; format = -1; switch(device->FmtType) { case DevFmtByte: format = SND_PCM_FORMAT_S8; break; case DevFmtUByte: format = SND_PCM_FORMAT_U8; break; case DevFmtShort: format = SND_PCM_FORMAT_S16; break; case DevFmtUShort: format = SND_PCM_FORMAT_U16; break; case DevFmtInt: format = SND_PCM_FORMAT_S32; break; case DevFmtUInt: format = SND_PCM_FORMAT_U32; break; case DevFmtFloat: format = SND_PCM_FORMAT_FLOAT; break; } allowmmap = GetConfigValueBool("alsa", "mmap", 1); periods = device->NumUpdates; periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; bufferLen = periodLen * periods; rate = device->Frequency; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); /* set interleaved access */ if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { if(periods > 2) { periods--; bufferLen = periodLen * periods; } CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); } /* test and set format (implicitly sets sample bits) */ if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0) { static const struct { snd_pcm_format_t format; enum DevFmtType fmttype; } formatlist[] = { { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, { SND_PCM_FORMAT_S32, DevFmtInt }, { SND_PCM_FORMAT_U32, DevFmtUInt }, { SND_PCM_FORMAT_S16, DevFmtShort }, { SND_PCM_FORMAT_U16, DevFmtUShort }, { SND_PCM_FORMAT_S8, DevFmtByte }, { SND_PCM_FORMAT_U8, DevFmtUByte }, }; size_t k; for(k = 0;k < COUNTOF(formatlist);k++) { format = formatlist[k].format; if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0) { device->FmtType = formatlist[k].fmttype; break; } } } CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); /* test and set channels (implicitly sets frame bits) */ if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0) { static const enum DevFmtChannels channellist[] = { DevFmtStereo, DevFmtQuad, DevFmtX51, DevFmtX71, DevFmtMono, }; size_t k; for(k = 0;k < COUNTOF(channellist);k++) { if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0) { device->FmtChans = channellist[k]; break; } } } CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0) ERR("Failed to disable ALSA resampler\n"); CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL)); /* set buffer time (implicitly constrains period/buffer parameters) */ CHECK(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL)); /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ CHECK(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL)); /* install and prepare hardware configuration */ CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL)); snd_pcm_hw_params_free(hp); hp = NULL; snd_pcm_sw_params_malloc(&sp); CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp)); CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)); CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods)); CHECK(snd_pcm_sw_params(data->pcmHandle, sp)); #undef CHECK snd_pcm_sw_params_free(sp); sp = NULL; /* Increase periods by one, since the temp buffer counts as an extra * period */ if(access == SND_PCM_ACCESS_RW_INTERLEAVED) device->NumUpdates = periods+1; else device->NumUpdates = periods; device->UpdateSize = periodSizeInFrames; device->Frequency = rate; SetDefaultChannelOrder(device); return ALC_TRUE; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); if(sp) snd_pcm_sw_params_free(sp); return ALC_FALSE; }
/** * 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 ") + ToString(Fragments) + " 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(); } }
/** * Allocate the memory-mapped buffer for direct sound, and set up the * callback. */ static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi) { snd_pcm_t *pcm = pdbi->pcm; snd_pcm_format_t format; snd_pcm_uframes_t frames, ofs, avail, psize, boundary; unsigned int channels, bits_per_sample, bits_per_frame; int err, mmap_mode; const snd_pcm_channel_area_t *areas; snd_pcm_hw_params_t *hw_params = pdbi->hw_params; snd_pcm_sw_params_t *sw_params = pdbi->sw_params; void *buf; mmap_mode = snd_pcm_type(pcm); if (mmap_mode == SND_PCM_TYPE_HW) TRACE("mmap'd buffer is a direct hardware buffer.\n"); else if (mmap_mode == SND_PCM_TYPE_DMIX) TRACE("mmap'd buffer is an ALSA dmix buffer\n"); else TRACE("mmap'd buffer is an ALSA type %d buffer\n", mmap_mode); err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL); err = snd_pcm_hw_params_get_format(hw_params, &format); err = snd_pcm_hw_params_get_buffer_size(hw_params, &frames); err = snd_pcm_hw_params_get_channels(hw_params, &channels); bits_per_sample = snd_pcm_format_physical_width(format); bits_per_frame = bits_per_sample * channels; if (TRACE_ON(dsalsa)) ALSA_TraceParameters(hw_params, NULL, FALSE); TRACE("format=%s frames=%ld channels=%d bits_per_sample=%d bits_per_frame=%d\n", snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame); pdbi->mmap_buflen_frames = frames; pdbi->mmap_buflen_bytes = snd_pcm_frames_to_bytes( pcm, frames ); snd_pcm_sw_params_current(pcm, sw_params); snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 0); snd_pcm_sw_params_get_boundary(sw_params, &boundary); snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary); snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, boundary); snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0); snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0); err = snd_pcm_sw_params(pcm, sw_params); avail = snd_pcm_avail_update(pcm); if ((snd_pcm_sframes_t)avail < 0) { ERR("No buffer is available: %s.\n", snd_strerror(avail)); return DSERR_GENERIC; } if (!pdbi->mmap) { buf = pdbi->mmap_buffer = HeapAlloc(GetProcessHeap(), 0, pdbi->mmap_buflen_bytes); if (!buf) return DSERR_OUTOFMEMORY; snd_pcm_format_set_silence(format, buf, pdbi->mmap_buflen_frames); pdbi->mmap_pos = 0; } else { err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail); if ( err < 0 ) { ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err); return DSERR_GENERIC; } snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames); pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0); pdbi->mmap_buffer = areas->addr; } TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n", frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer); return DS_OK; }
bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize) { if (handle == nullptr) return false; JUCE_ALSA_LOG ("ALSADevice::setParameters(" << deviceID << ", " << (int) sampleRate << ", " << numChannels << ", " << bufferSize << ")"); snd_pcm_hw_params_t* hwParams; snd_pcm_hw_params_alloca (&hwParams); if (snd_pcm_hw_params_any (handle, hwParams) < 0) { // this is the error message that aplay returns when an error happens here, // it is a bit more explicit that "Invalid parameter" error = "Broken configuration for this PCM: no configurations available"; return false; } if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0) // works better for plughw.. isInterleaved = true; else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0) isInterleaved = false; else { jassertfalse; return false; } enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17, onlyUseLower24Bits = 1 << 18 }; const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32 | isFloatBit | isLittleEndianBit, SND_PCM_FORMAT_FLOAT_BE, 32 | isFloatBit, SND_PCM_FORMAT_S32_LE, 32 | isLittleEndianBit, SND_PCM_FORMAT_S32_BE, 32, SND_PCM_FORMAT_S24_3LE, 24 | isLittleEndianBit, SND_PCM_FORMAT_S24_3BE, 24, SND_PCM_FORMAT_S24_LE, 32 | isLittleEndianBit | onlyUseLower24Bits, SND_PCM_FORMAT_S16_LE, 16 | isLittleEndianBit, SND_PCM_FORMAT_S16_BE, 16 }; bitDepth = 0; for (int i = 0; i < numElementsInArray (formatsToTry); i += 2) { if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0) { const int type = formatsToTry [i + 1]; bitDepth = type & 255; converter.reset (createConverter (isInput, bitDepth, (type & isFloatBit) != 0, (type & isLittleEndianBit) != 0, (type & onlyUseLower24Bits) != 0, numChannels, isInterleaved)); break; } } if (bitDepth == 0) { error = "device doesn't support a compatible PCM format"; JUCE_ALSA_LOG ("Error: " + error); return false; } int dir = 0; unsigned int periods = 4; snd_pcm_uframes_t samplesPerPeriod = (snd_pcm_uframes_t) bufferSize; if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, (unsigned int ) numChannels)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir)) || JUCE_ALSA_FAILED (snd_pcm_hw_params (handle, hwParams))) { return false; } snd_pcm_uframes_t frames = 0; if (JUCE_ALSA_FAILED (snd_pcm_hw_params_get_period_size (hwParams, &frames, &dir)) || JUCE_ALSA_FAILED (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir))) latency = 0; else latency = (int) frames * ((int) periods - 1); // (this is the method JACK uses to guess the latency..) JUCE_ALSA_LOG ("frames: " << (int) frames << ", periods: " << (int) periods << ", samplesPerPeriod: " << (int) samplesPerPeriod); snd_pcm_sw_params_t* swParams; snd_pcm_sw_params_alloca (&swParams); snd_pcm_uframes_t boundary; if (JUCE_ALSA_FAILED (snd_pcm_sw_params_current (handle, swParams)) || JUCE_ALSA_FAILED (snd_pcm_sw_params_get_boundary (swParams, &boundary)) || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0)) || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary)) || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod)) || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary)) || JUCE_ALSA_FAILED (snd_pcm_sw_params (handle, swParams))) { return false; } #if JUCE_ALSA_LOGGING // enable this to dump the config of the devices that get opened snd_output_t* out; snd_output_stdio_attach (&out, stderr, 0); snd_pcm_hw_params_dump (hwParams, out); snd_pcm_sw_params_dump (swParams, out); #endif numChannelsRunning = numChannels; return true; }
/* 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
static int sndo_pcm_initialize(sndo_pcm_t *pcm) { int err; snd_pcm_uframes_t boundary; snd_pcm_uframes_t p_period_size = ~0UL, c_period_size = ~0UL; snd_pcm_uframes_t p_buffer_size = ~0UL, c_buffer_size = ~0UL; if (pcm->playback) { err = snd_pcm_hw_params(pcm->playback, pcm->p_hw_params); if (err < 0) return err; err = snd_pcm_hw_params_get_period_size(pcm->p_hw_params, &p_period_size, NULL); if (err < 0) return err; err = snd_pcm_hw_params_get_buffer_size(pcm->p_hw_params, &p_buffer_size); if (err < 0) return err; } if (pcm->capture) { err = snd_pcm_hw_params(pcm->capture, pcm->c_hw_params); if (err < 0) return err; err = snd_pcm_hw_params_get_period_size(pcm->c_hw_params, &c_period_size, NULL); if (err < 0) return err; err = snd_pcm_hw_params_get_buffer_size(pcm->c_hw_params, &c_buffer_size); if (err < 0) return err; } if (p_period_size < c_period_size) pcm->transfer_block = p_period_size; else pcm->transfer_block = c_period_size; if (p_buffer_size < c_buffer_size) pcm->ring_size = p_buffer_size; else pcm->ring_size = c_buffer_size; if (pcm->playback) { err = snd_pcm_sw_params_get_boundary(pcm->p_sw_params, &boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_start_threshold(pcm->playback, pcm->p_sw_params, boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_stop_threshold(pcm->playback, pcm->p_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size); if (err < 0) return err; err = snd_pcm_sw_params_set_xfer_align(pcm->playback, pcm->p_sw_params, 1); if (err < 0) return err; err = snd_pcm_sw_params_set_avail_min(pcm->playback, pcm->p_sw_params, pcm->transfer_block); if (err < 0) return err; err = snd_pcm_sw_params(pcm->playback, pcm->p_sw_params); if (err < 0) return err; } if (pcm->capture) { err = snd_pcm_sw_params_get_boundary(pcm->c_sw_params, &boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_start_threshold(pcm->capture, pcm->c_sw_params, boundary); if (err < 0) return err; err = snd_pcm_sw_params_set_stop_threshold(pcm->capture, pcm->c_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size); if (err < 0) return err; err = snd_pcm_sw_params_set_xfer_align(pcm->capture, pcm->c_sw_params, 1); if (err < 0) return err; err = snd_pcm_sw_params_set_avail_min(pcm->capture, pcm->c_sw_params, pcm->transfer_block); if (err < 0) return err; err = snd_pcm_sw_params(pcm->capture, pcm->c_sw_params); if (err < 0) return err; } pcm->initialized = 1; return 0; }
status_t setSoftwareParams(alsa_handle_t *handle) { snd_pcm_sw_params_t * softwareParams; int err; snd_pcm_uframes_t bufferSize = 0; snd_pcm_uframes_t periodSize = 0; snd_pcm_uframes_t startThreshold, stopThreshold; if (snd_pcm_sw_params_malloc(&softwareParams) < 0) { LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!"); return NO_INIT; } // Get the current software parameters err = snd_pcm_sw_params_current(handle->handle, softwareParams); if (err < 0) { LOGE("Unable to get software parameters: %s", snd_strerror(err)); goto done; } // Configure ALSA to start the transfer when the buffer is almost full. snd_pcm_get_params(handle->handle, &bufferSize, &periodSize); if (handle->devices & AudioSystem::DEVICE_OUT_ALL) { // For playback, configure ALSA to start the transfer when the // buffer is full. startThreshold = bufferSize - 1; stopThreshold = bufferSize; } else { // For recording, configure ALSA to start the transfer on the // first frame. startThreshold = 1; stopThreshold = bufferSize; } err = snd_pcm_sw_params_set_start_threshold(handle->handle, softwareParams, startThreshold); if (err < 0) { LOGE("Unable to set start threshold to %lu frames: %s", startThreshold, snd_strerror(err)); goto done; } err = snd_pcm_sw_params_set_stop_threshold(handle->handle, softwareParams, stopThreshold); if (err < 0) { LOGE("Unable to set stop threshold to %lu frames: %s", stopThreshold, snd_strerror(err)); goto done; } // Allow the transfer to start when at least periodSize samples can be // processed. err = snd_pcm_sw_params_set_avail_min(handle->handle, softwareParams, periodSize); if (err < 0) { LOGE("Unable to configure available minimum to %lu: %s", periodSize, snd_strerror(err)); goto done; } // Commit the software parameters back to the device. err = snd_pcm_sw_params(handle->handle, softwareParams); if (err < 0) LOGE("Unable to configure software parameters: %s", snd_strerror(err)); done: snd_pcm_sw_params_free(softwareParams); return err; }
static size_t alsa_configure (void) { //<init: size_t chunk_bytes, bits_per_sample, bits_per_frame = 0; snd_pcm_uframes_t chunk_size, buffer_size = 0; snd_pcm_hw_params_t *params; unsigned int rate = DEFAULT_SPEED; int err; snd_pcm_hw_params_alloca (¶ms); //> //<defaults: err = snd_pcm_hw_params_any (AHandle, params); if (err < 0) { fprintf (stderr, "Broken configuration for this PCM: no configurations available"); exit (EXIT_FAILURE); } //> //<Format: err = snd_pcm_hw_params_set_format (AHandle, params, DEFAULT_FORMAT); if (err < 0) { fprintf (stderr, "Sample format non available"); exit (EXIT_FAILURE); } //> //<Channels: err = snd_pcm_hw_params_set_channels (AHandle, params, 1); if (err < 0) { fprintf (stderr, "Channels count non available"); exit (EXIT_FAILURE); } //> //<Rate: err = snd_pcm_hw_params_set_rate_near (AHandle, params, &rate, 0); assert (err >= 0); //> //<Access Mode: err = snd_pcm_hw_params_set_access (AHandle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { fprintf (stderr, "Access type not available"); exit (EXIT_FAILURE); } //> //< Set things explicitly if DEBUG #ifdef DEBUG //<Compute buffer_time: unsigned int period_time = 0; unsigned int buffer_time = 0; snd_pcm_uframes_t period_frames = 0; snd_pcm_uframes_t buffer_frames = 0; // affected by defined buffer_size (e.g. via asoundrc) if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time (params, &buffer_time, 0); assert (err >= 0); if (buffer_time > 500000) //usecs buffer_time = 500000; } //> //<Compute period_time: if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near (AHandle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near (AHandle, params, &period_frames, 0); assert (err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near (AHandle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near (AHandle, params, &buffer_frames); } assert (err >= 0); //> #endif //> //<Commit hw params: err = snd_pcm_hw_params (AHandle, params); if (err < 0) { fprintf (stderr, "Unable to install hw params:"); exit (EXIT_FAILURE); } //> //<finalize chunk_size and buffer_size: snd_pcm_hw_params_get_period_size (params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size (params, &buffer_size); if (chunk_size == buffer_size) { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit (EXIT_FAILURE); } //> //< If DEBUG: SW Params Configure transfer: #ifdef DEBUG size_t n; snd_pcm_uframes_t xfer_align; snd_pcm_uframes_t start_threshold, stop_threshold; int start_delay = 5; int stop_delay = 0; snd_pcm_sw_params_t *swParams; snd_pcm_sw_params_alloca (&swParams); snd_pcm_sw_params_current (AHandle, swParams); err = snd_pcm_sw_params_get_xfer_align (swParams, &xfer_align); if (err < 0) { fprintf (stderr, "Unable to obtain xfer align\n"); exit (EXIT_FAILURE); } // round up to closest transfer boundary n = (buffer_size / xfer_align) * xfer_align; if (start_delay <= 0) { start_threshold = (snd_pcm_uframes_t) (n + (double) rate * start_delay / 1000000); } else start_threshold = (snd_pcm_uframes_t) ((double) rate * start_delay / 1000000); if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold (AHandle, swParams, start_threshold); assert (err >= 0); if (stop_delay <= 0) stop_threshold = (snd_pcm_uframes_t) (buffer_size + (double) rate * stop_delay / 1000000); else stop_threshold = (snd_pcm_uframes_t) ((double) rate * stop_delay / 1000000); err = snd_pcm_sw_params_set_stop_threshold (AHandle, swParams, stop_threshold); assert (err >= 0); err = snd_pcm_sw_params_set_xfer_align (AHandle, swParams, xfer_align); assert (err >= 0); if (snd_pcm_sw_params (AHandle, swParams) < 0) { fprintf (stderr, "unable to install sw params:"); exit (EXIT_FAILURE); } #endif //> bits_per_sample = snd_pcm_format_physical_width (DEFAULT_FORMAT); bits_per_frame = bits_per_sample * 1; //mono chunk_bytes = chunk_size * bits_per_frame / 8; return chunk_bytes; }
static int sa_alsa_open_stream( simpleaudio *sa, const char *backend_device, sa_direction_t sa_stream_direction, sa_format_t sa_format, unsigned int rate, unsigned int channels, char *app_name, char *stream_name ) { snd_pcm_t *pcm; int error; char *be_device; if ( ! backend_device ) { be_device = "default"; } else { be_device = alloca(32); if ( strchr(backend_device, ':') ) snprintf(be_device, 32, "%s", backend_device); else if ( strchr(backend_device, ',') ) snprintf(be_device, 32, "plughw:%s", backend_device); else snprintf(be_device, 32, "plughw:%s,0", backend_device); } error = snd_pcm_open(&pcm, be_device, sa_stream_direction == SA_STREAM_RECORD ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0 /*mode*/); if (error) { fprintf(stderr, "E: Cannot create ALSA stream: %s\n", snd_strerror(error)); return 0; } snd_pcm_format_t pcm_format; switch ( sa->format ) { case SA_SAMPLE_FORMAT_FLOAT: pcm_format = SND_PCM_FORMAT_FLOAT; break; case SA_SAMPLE_FORMAT_S16: pcm_format = SND_PCM_FORMAT_S16; break; default: assert(0); } /* set up ALSA hardware params */ error = snd_pcm_set_params(pcm, pcm_format, SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 1 /* soft_resample (allow) */, (unsigned int)-1 /* latency (allow max to avoid underruns) */); if (error) { fprintf(stderr, "E: %s\n", snd_strerror(error)); snd_pcm_close(pcm); return 0; } #if 0 snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); error = snd_pcm_sw_params_current(pcm, swparams); if (error) { fprintf(stderr, "E: %s\n", snd_strerror(error)); snd_pcm_close(pcm); return NULL; } snd_pcm_sw_params_set_start_threshold(pcm, swparams, NFRAMES_VAL); snd_pcm_sw_params_set_stop_threshold(pcm, swparams, NFRAMES_VAL); snd_pcm_sw_params_set_silence_threshold(pcm, swparams, NFRAMES_VAL); error = snd_pcm_sw_params(pcm, swparams); if (error) { fprintf(stderr, "E: %s\n", snd_strerror(error)); snd_pcm_close(pcm); return NULL; } #endif sa->backend_handle = pcm; sa->backend_framesize = sa->channels * sa->samplesize; return 1; }
static int alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate) { snd_pcm_hw_params_t *hwparams=NULL; snd_pcm_sw_params_t *swparams=NULL; int dir; uint exact_uvalue; unsigned long exact_ulvalue; int channels; int periods=ALSA_PERIODS; int periodsize=ALSA_PERIOD_SIZE; int err; int format; /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca(&hwparams); /* Init hwparams with full configuration space */ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { ms_warning("alsa_set_params: Cannot configure this PCM device.\n"); return -1; } if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { ms_warning("alsa_set_params: Error setting access.\n"); return -1; } /* Set sample format */ format=SND_PCM_FORMAT_S16; if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) { ms_warning("alsa_set_params: Error setting format.\n"); return -1; } /* Set number of channels */ if (stereo) channels=2; else channels=1; if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) { ms_warning("alsa_set_params: Error setting channels.\n"); return -1; } /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_uvalue=rate; dir=0; if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){ ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err)); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n " "==> Using %d Hz instead.\n", rate, exact_uvalue); } /* choose greater period size when rate is high */ periodsize=periodsize*(rate/8000); /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ /* set period size */ exact_ulvalue=periodsize; dir=0; if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) { ms_warning("alsa_set_params: Error setting period size.\n"); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n " "==> Using %d instead.\n", periodsize, (int)exact_ulvalue); } periodsize=exact_ulvalue; /* Set number of periods. Periods used to be called fragments. */ exact_uvalue=periods; dir=0; if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) { ms_warning("alsa_set_params: Error setting periods.\n"); return -1; } if (dir != 0) { ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n " "==> Using %d instead.\n", periods, exact_uvalue); } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err)); return -1; } /*prepare sw params */ if (rw){ snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(pcm_handle, swparams); if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*4 ))<0){ ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); } if ((err=snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,periodsize*periods ))<0){ ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err)); } if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){ ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err)); return -1; } } return 0; }
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=-1; int count=0; unsigned int freakuency=settings.frequency(); QString dev = 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().constData()); #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 ) { 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; }
static void *_msynth_thread_main(void *arg) { int i; int err; int sample; int processed; struct sampleclock sc = {0, 0, 0.0f, 0.0f}; msynth_frame fb = NULL; puts("synthread: started"); /* Begin initialization of ALSA */ /* snd_pcm_open(pcm_handle, device_name, stream_type, open_mode) */ err = snd_pcm_open(&pcm, config.device_name, SND_PCM_STREAM_PLAYBACK, 0); ALSERT("opening audio device"); /* First ALSA hardware settings */ /* Allocate HW params */ err = snd_pcm_hw_params_malloc(&hw_p); ALSERT("allocating hw params"); /* Get default HW parameters */ err = snd_pcm_hw_params_any(pcm, hw_p); ALSERT("requesting hw default params"); /* Disable software resampling */ err = snd_pcm_hw_params_set_rate_resample(pcm, hw_p, config.resample); ALSERT("disabling software resampling"); /* Configure sample rate */ if (config.srate != -1) srate = config.srate; else { /* Get maximum hardware samplerate */ err = snd_pcm_hw_params_get_rate_max(hw_p, &srate, &dir); ALSERT("requesting maximum hardware samplerate"); } /* Set sample rate * snd_pcm_hw_params_set_rate_near(pcn, hw_p, *rate, * 0 (== set exact rate)) */ err = snd_pcm_hw_params_set_rate_near(pcm, hw_p, &srate, 0); ALSERT("setting samplerate"); printf("synthread: Detected samplerate of %u\n", srate); /* RW interleaved access (means we will use the snd_pcm_writei function) */ err = snd_pcm_hw_params_set_access(pcm, hw_p, SND_PCM_ACCESS_RW_INTERLEAVED); ALSERT("setting access mode"); /* native-endian 16-bit signed sample format */ err = snd_pcm_hw_params_set_format(pcm, hw_p, SND_PCM_FORMAT_S16); ALSERT("setting sample format"); /* Switch to 2.0ch audio */ err = snd_pcm_hw_params_set_channels(pcm, hw_p, 2); ALSERT("switching to 2.0ch audio"); if (config.buffer_time != -1) { /* Set configured buffer time */ err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw_p, &config.buffer_time, &dir); ALSERT("setting buffer time"); /* Fetch resulting size */ err = snd_pcm_hw_params_get_buffer_size(hw_p, &buffer_size); ALSERT("getting buffer size"); } else { /* Since we want the interactive synthesizer to be very responsive * select a minimum buffer size. */ err = snd_pcm_hw_params_set_buffer_size_first(pcm, hw_p, &buffer_size); ALSERT("setting buffer size"); } printf("synthread: Selected buffersize of %lu\n", buffer_size); printf("synthread: Response delay is approximately %.2f ms\n", (double)buffer_size / (double)srate * 1000.0); if (config.period_time != -1) { err = snd_pcm_hw_params_set_period_time_near(pcm, hw_p, &config.period_time, &dir); ALSERT("setting period time"); err = snd_pcm_hw_params_get_period_size(hw_p, &period_size, &dir); ALSERT("getting period size"); } else { /* Select a period time of half the buffer time * since this improves processing performance */ err = snd_pcm_hw_params_set_period_size_last(pcm, hw_p, &period_size, &dir); ALSERT("setting period size"); } if (dir) printf("synthread: Selected period size near %lu\n", period_size); else printf("synthread: Selected period size of %lu\n", period_size); /* write hw parameters to device */ err = snd_pcm_hw_params(pcm, hw_p); ALSERT("writing hw params"); /* Begin ALSA software side setup */ /* Allocate SW params */ err = snd_pcm_sw_params_malloc(&sw_p); ALSERT("allocating sw params"); /* Request software current settings */ err = snd_pcm_sw_params_current(pcm, sw_p); ALSERT("requesting current sw params"); /* Automatically start playing after the first period is written */ err = snd_pcm_sw_params_set_start_threshold(pcm, sw_p, period_size); ALSERT("settings start threshold"); /* XRUN when buffer is empty */ err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_p, buffer_size * 2); ALSERT("setting stop threshold"); /* Block synthesizer when there is not at least period frames available */ err = snd_pcm_sw_params_set_avail_min(pcm, sw_p, period_size); ALSERT("setting minimum free frames"); /* Write software parameters */ err = snd_pcm_sw_params(pcm, sw_p); ALSERT("writing sw params"); printf("synthread: Audio system configured.\n"); /* Prepare device for playback */ err = snd_pcm_prepare(pcm); ALSERT("preparing device"); /* Allocate a period sized framebuffer * (yup an audio buffer is in ALSA speak indeed called a framebuffer) */ fb = malloc(sizeof(struct _msynth_frame) * period_size); if (!fb) { perror("malloc framebuffer failed"); exit(1); } /* Set sampleclock to 0 */ sc.samples = 0; sc.samplerate = srate; sc.cycle = 0.0f; sc.seconds = 0.0f; /* Initially the <root> variable describing the flow of sound within * the synthesizer is configured to be a NULL signal. (silence) */ /* Signal successful completion of initialization */ pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); /* -------------- Main loop --------------- */ while (!shutdown) { /* Only during generation we need the synth tree to be static */ synth_lock_graphs(); for (i = 0; i < period_size; i++) { /* Evaluate variables */ ssv_eval(sc); sample = (int)(32767.5 * ssv_get_var_eval("left") * volume); /* Clip samples */ if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; fb[i].left = (short)sample; sample = (int)(32767.5 * ssv_get_var_eval("right") * volume); /* Clip samples */ if (sample > 32767) sample = 32767; if (sample < -32768) sample = -32768; fb[i].right = (short)sample; sc = sc_from_samples(sc.samplerate, sc.samples + 1); } synth_unlock_graphs(); /* Send audio to sound card */ processed = 0; while (processed != period_size) { err = snd_pcm_writei(pcm, fb + processed, period_size - processed); /* Retry on interruption by signal */ if (err == -EAGAIN) continue; /* Recover from XRUN/suspend */ if (err < 0) { err = synth_recover(err); ALSERT("sending audio"); continue; } /* Update processed samples */ processed += err; } } puts("synthread: shutting down"); /* Dump any statistics recorded */ if (recover_resumes) printf("synthread: Device was resumed %i times\n", recover_resumes); if (recover_xruns) printf("synthread: %i xrun recoveries were needed\n", recover_xruns); printf("synthread: processed %i samples\n", sc.samples); /* Wait for playback to complete */ err = snd_pcm_drain(pcm); ALSERT("draining device"); /* Shutdown PCM device */ err = snd_pcm_close(pcm); ALSERT("closing audio device"); /* Clean up parameters */ snd_pcm_hw_params_free(hw_p); snd_pcm_sw_params_free(sw_p); return NULL; }
/* set up an input or output device. Return 0 on success, -1 on failure. */ static int alsaio_setup(t_alsa_dev *dev, int out, int *channels, int *rate, int nfrags, int frag_size) { int bufsizeforthis, err; snd_pcm_hw_params_t* hw_params; snd_pcm_sw_params_t* sw_params; unsigned int tmp_uint; snd_pcm_uframes_t tmp_snd_pcm_uframes; snd_pcm_hw_params_alloca(&hw_params); snd_pcm_sw_params_alloca(&sw_params); if (sys_verbose) post((out ? "configuring sound output..." : "configuring sound input...")); /* set hardware parameters... */ /* get the default params */ err = snd_pcm_hw_params_any(dev->a_handle, hw_params); check_error(err, out, "snd_pcm_hw_params_any"); /* try to set interleaved access */ err = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) return (-1); check_error(err, out, "snd_pcm_hw_params_set_access"); #if 0 /* enable this to print out which formats are available */ { int i; for (i = 0; i <= SND_PCM_FORMAT_LAST; i++) fprintf(stderr, "%d -> %d\n", i, snd_pcm_hw_params_test_format(dev->a_handle, hw_params, i)); } #endif /* Try to set 32 bit format first */ err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, SND_PCM_FORMAT_S32); if (err < 0) { err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, SND_PCM_FORMAT_S24_3LE); if (err < 0) { err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, SND_PCM_FORMAT_S16); check_error(err, out, "_pcm_hw_params_set_format"); dev->a_sampwidth = 2; } else dev->a_sampwidth = 3; } else dev->a_sampwidth = 4; if (sys_verbose) post("Sample width set to %d bytes", dev->a_sampwidth); /* set the subformat */ err = snd_pcm_hw_params_set_subformat(dev->a_handle, hw_params, SND_PCM_SUBFORMAT_STD); check_error(err, out, "snd_pcm_hw_params_set_subformat"); /* set the number of channels */ tmp_uint = *channels; err = snd_pcm_hw_params_set_channels_near(dev->a_handle, hw_params, &tmp_uint); check_error(err, out, "snd_pcm_hw_params_set_channels"); if (tmp_uint != (unsigned)*channels) post("ALSA: set %s channels to %d", (out?"output":"input"), tmp_uint); *channels = tmp_uint; dev->a_channels = *channels; /* set the sampling rate */ err = snd_pcm_hw_params_set_rate_near(dev->a_handle, hw_params, (unsigned int *)rate, 0); check_error(err, out, "snd_pcm_hw_params_set_rate_min"); #if 0 err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir); post("input sample rate %d", err); #endif /* post("frag size %d, nfrags %d", frag_size, nfrags); */ /* set "period size" */ tmp_snd_pcm_uframes = frag_size; err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes, 0); check_error(err, out, "snd_pcm_hw_params_set_period_size_near"); /* set the buffer size */ tmp_snd_pcm_uframes = nfrags * frag_size; err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes); check_error(err, out, "snd_pcm_hw_params_set_buffer_size_near"); err = snd_pcm_hw_params(dev->a_handle, hw_params); check_error(err, out, "snd_pcm_hw_params"); /* set up the buffer */ bufsizeforthis = DEFDACBLKSIZE * dev->a_sampwidth * *channels; if (alsa_snd_buf) { if (alsa_snd_bufsize < bufsizeforthis) { if (!(alsa_snd_buf = realloc(alsa_snd_buf, bufsizeforthis))) { post("out of memory"); return (-1); } memset(alsa_snd_buf, 0, bufsizeforthis); alsa_snd_bufsize = bufsizeforthis; } } else { if (!(alsa_snd_buf = (void *)malloc(bufsizeforthis))) { post("out of memory"); return (-1); } memset(alsa_snd_buf, 0, bufsizeforthis); alsa_snd_bufsize = bufsizeforthis; } err = snd_pcm_sw_params_current(dev->a_handle, sw_params); if (err < 0) { post("Unable to determine current swparams for %s: %s\n", (out ? "output" : "input"), snd_strerror(err)); return (-1); } err = snd_pcm_sw_params_set_stop_threshold(dev->a_handle, sw_params, 0x7fffffff); if (err < 0) { post("Unable to set start threshold mode for %s: %s\n", (out ? "output" : "input"), snd_strerror(err)); return (-1); } err = snd_pcm_sw_params_set_avail_min(dev->a_handle, sw_params, 4); if (err < 0) { post("Unable to set avail min for %s: %s\n", (out ? "output" : "input"), snd_strerror(err)); return (-1); } err = snd_pcm_sw_params(dev->a_handle, sw_params); if (err < 0) { post("Unable to set sw params for %s: %s\n", (out ? "output" : "input"), snd_strerror(err)); return (-1); } return (0); }
static int aplaypop_open(void) { int err; snd_pcm_t *handle; if (pcm_handle) return 0; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); snd_output_t *log; err = snd_output_stdio_attach(&log, stderr, 0); assert(err == 0); err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0); if (err != 0) { fprintf(stderr, "snd_pcm_open(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_nonblock(handle, 0); if (err != 0) { fprintf(stderr, "snd_pcm_nonblock(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_info(handle, info); if (err != 0) { fprintf(stderr, "snd_pcm_info(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // DOESN'T WORK! err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS, RATE, 1, 50000); if (err != 0) { fprintf(stderr, "snd_pcm_set_params(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // RIGHT WAY: snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; unsigned int channels = CHANNELS; unsigned int rate = RATE; 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)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_access(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_format(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_channels(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_rate_near(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } /* unsigned buffer_time = 0; snd_pcm_uframes_t buffer_frames = 0; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); assert(err == 0); if (buffer_time > 500000) buffer_time = 500000; } unsigned period_time = 0; snd_pcm_uframes_t period_frames = 0; if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0); assert(err == 0); if (buffer_time > 0) err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); else err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames); assert(err == 0); int monotonic = snd_pcm_hw_params_is_monotonic(hwparams); int can_pause = snd_pcm_hw_params_can_pause(hwparams); */ err = snd_pcm_hw_params(handle, hwparams); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params(): %s\n", snd_strerror(err)); snd_pcm_hw_params_dump(hwparams, log); exit(EXIT_FAILURE); } snd_pcm_uframes_t chunk_size = 0; snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (chunk_size == buffer_size) { fprintf(stderr, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size); assert(err == 0); /* round up to closest transfer boundary */ int start_delay = 0; snd_pcm_uframes_t start_threshold; if (start_delay <= 0) start_threshold = buffer_size + (double) rate * start_delay / 1000000; else start_threshold = (double) rate * start_delay / 1000000; start_threshold = start_threshold < 1 ? 1 : start_threshold > buffer_size ? buffer_size : start_threshold; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err == 0); int stop_delay = 0; snd_pcm_uframes_t stop_threshold; if (stop_delay <= 0) stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; else stop_threshold = (double) rate * stop_delay / 1000000; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err == 0); err = snd_pcm_sw_params(handle, swparams); if (err != 0) { fprintf(stderr, "snd_pcm_sw_params(): %s\n", snd_strerror(err)); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } // END OF THE RIGHT WAY // snd_pcm_dump(handle, log); size_t bits_per_sample = snd_pcm_format_physical_width(format); size_t bits_per_frame = bits_per_sample * channels; size_t chunk_bytes = chunk_size * bits_per_frame / 8; //audiobuf = realloc(audiobuf, chunk_bytes); fprintf(stderr, "%s: %s, Rate %d Hz, Channels=%u\n", snd_pcm_format_name(format), snd_pcm_format_description(format), rate, channels); fprintf(stderr, " bits_per_sample=%u, bits_per_frame=%u, chunk_bytes=%u\n", bits_per_sample, bits_per_frame, chunk_bytes); frame_bytes = bits_per_frame / 8; pcm_handle = handle; return 0; }
bool QAlsaAudioInput::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 sampleRate=settings.sampleRate(); if (!settings.isValid()) { qWarning("QAudioInput: open error, invalid format."); } else if (settings.sampleRate() <= 0) { qWarning("QAudioInput: open error, invalid sample rate (%d).", settings.sampleRate()); } else { err = -1; } if (err == 0) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; emit errorChanged(errorState); return false; } QString dev = QString(QLatin1String(m_device.constData())); QList<QByteArray> devices = QAlsaAudioDeviceInfo::availableDevices(QAudio::AudioInput); if(dev.compare(QLatin1String("default")) == 0) { #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) if (devices.size() > 0) dev = QLatin1String(devices.first()); else return false; #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.channelCount() ); 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, &sampleRate, 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 ringBuffer.resize(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; }
static int initialize_device(struct audio_info_struct *ai) { snd_pcm_hw_params_t *hw; int i; snd_pcm_format_t format; unsigned int rate; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; snd_pcm_sw_params_t *sw; snd_pcm_uframes_t boundary; snd_pcm_hw_params_alloca(&hw); if (snd_pcm_hw_params_any(ai->handle, hw) < 0) { fprintf(stderr, "initialize_device(): no configuration available\n"); return -1; } if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { fprintf(stderr, "initialize_device(): device does not support interleaved access\n"); return -1; } format = SND_PCM_FORMAT_UNKNOWN; for (i = 0; i < NUM_FORMATS; ++i) { if (ai->format == format_map[i].mpg123) { format = format_map[i].alsa; break; } } if (format == SND_PCM_FORMAT_UNKNOWN) { fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format); errno = EINVAL; return -1; } if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) { fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format)); return -1; } if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) { fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels); return -1; } rate = ai->rate; if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) { fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate); return -1; } if (!rates_match(ai->rate, rate)) { fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate); /* return -1; */ } buffer_size = rate * BUFFER_LENGTH; if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) { fprintf(stderr, "initialize_device(): cannot set buffer size\n"); return -1; } period_size = buffer_size / 4; if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) { fprintf(stderr, "initialize_device(): cannot set period size\n"); return -1; } if (snd_pcm_hw_params(ai->handle, hw) < 0) { fprintf(stderr, "initialize_device(): cannot set hw params\n"); return -1; } snd_pcm_sw_params_alloca(&sw); if (snd_pcm_sw_params_current(ai->handle, sw) < 0) { fprintf(stderr, "initialize_device(): cannot get sw params\n"); return -1; } /* start playing after the first write */ if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) { fprintf(stderr, "initialize_device(): cannot set start threshold\n"); return -1; } if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) { fprintf(stderr, "initialize_device(): cannot get boundary\n"); return -1; } /* never stop on underruns */ if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) { fprintf(stderr, "initialize_device(): cannot set stop threshold\n"); return -1; } /* wake up on every interrupt */ if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) { fprintf(stderr, "initialize_device(): cannot set min avail\n"); return -1; } #if 0 /* always write as many frames as possible */ if (snd_pcm_sw_params_set_xfer_align(ai->handle, sw, 1) < 0) { fprintf(stderr, "initialize_device(): cannot set transfer alignment\n"); return -1; } #endif /* play silence when there is an underrun */ if (snd_pcm_sw_params_set_silence_size(ai->handle, sw, boundary) < 0) { fprintf(stderr, "initialize_device(): cannot set silence size\n"); return -1; } if (snd_pcm_sw_params(ai->handle, sw) < 0) { fprintf(stderr, "initialize_device(): cannot set sw params\n"); return -1; } return 0; }
static snd_pcm_uframes_t set_params(snd_pcm_t *handle, snd_pcm_stream_t stream) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t chunk_size = 0; snd_pcm_uframes_t start_threshold; unsigned period_time = 0; unsigned buffer_time = 0; size_t chunk_bytes = 0; int err; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { printf("Broken configuration for this PCM: no configurations available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { printf("Access type not available"); exit(EXIT_FAILURE); } printf("format = %s, channels = %d, rate = %d\n", snd_pcm_format_name(hwparams.format),hwparams.channels,hwparams.rate); //err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { printf("Sample format non available"); exit(EXIT_FAILURE); } //err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); err = snd_pcm_hw_params_set_channels(handle, params, 2); if (err < 0) { printf("Channels count non available"); exit(EXIT_FAILURE); } #if 0 //add by yjc 2012/08/21 err = set_audio_clk_freq(hwparams.rate); if (err < 0){ printf("set_audio_clk_freq fail..........\n"); exit(EXIT_FAILURE); } #endif err = snd_pcm_hw_params_set_rate(handle, params, hwparams.rate, 0); if (err < 0) { printf("Rate non available"); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; period_time = buffer_time / 4; err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); assert(err >= 0); err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to install hw params:"); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); if (chunk_size == buffer_size) { printf("Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size); if(stream == SND_PCM_STREAM_PLAYBACK) start_threshold = (buffer_size / chunk_size) * chunk_size; else start_threshold = 1; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, buffer_size); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { printf("unable to install sw params:"); exit(EXIT_FAILURE); } //bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); //bits_per_frame = bits_per_sample * hwparams.channels; bits_per_frame = bits_per_sample * 2; chunk_bytes = chunk_size * bits_per_frame / 8; printf("chunk_size = %d,chunk_bytes = %d,buffer_size = %d\n\n", (int)chunk_size,chunk_bytes,(int)buffer_size); return chunk_size; }
int ai_alsa_setup(audio_in_t *ai) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size, period_size; int err; int dir; unsigned int rate; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(ai->alsa.handle, params); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n"); return -1; } err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n"); return -1; } err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n"); return -1; } err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); if (err < 0) { snd_pcm_hw_params_get_channels(params, &ai->channels); mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n", ai->channels); } else { ai->channels = ai->req_channels; } dir = 0; rate = ai->req_samplerate; err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set samplerate.\n"); } ai->samplerate = rate; dir = 0; ai->alsa.buffer_time = 1000000; err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, &ai->alsa.buffer_time, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set buffer time.\n"); } dir = 0; ai->alsa.period_time = ai->alsa.buffer_time / 4; err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, &ai->alsa.period_time, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set period time.\n"); } err = snd_pcm_hw_params(ai->alsa.handle, params); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware parameters: %s", snd_strerror(err)); snd_pcm_hw_params_dump(params, ai->alsa.log); return -1; } dir = -1; snd_pcm_hw_params_get_period_size(params, &period_size, &dir); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); ai->alsa.chunk_size = period_size; if (period_size == buffer_size) { mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size); return -1; } snd_pcm_sw_params_current(ai->alsa.handle, swparams); err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n"); snd_pcm_sw_params_dump(swparams, ai->alsa.log); return -1; } if (mp_msg_test(MSGT_TV, MSGL_V)) { snd_pcm_dump(ai->alsa.handle, ai->alsa.log); } ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; ai->samplesize = ai->alsa.bits_per_sample; ai->bytes_per_sample = ai->alsa.bits_per_sample/8; return 0; }
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int playback) { #ifndef ALSAAPI9 int err; snd_pcm_uframes_t ps,ops; snd_pcm_uframes_t bs,obs; /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { check_error(err,"Unable to determine current swparams for playback"); return err; } /* AUTOSTART: start the transfer on each write/commit ??? */ snd_pcm_sw_params_get_start_threshold(swparams, &obs); err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); if (err < 0) { check_error(err,"Unable to set start threshold mode"); return err; } snd_pcm_sw_params_get_start_threshold(swparams, &bs); #ifdef ALSAMM_DEBUG if(sys_verbose) post("sw_params: got start_thresh_hold= %d (was %d)",(int) bs,(int)obs); #endif /* AUTOSTOP: never stop the machine */ snd_pcm_sw_params_get_stop_threshold(swparams, &obs); err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, (snd_pcm_uframes_t)-1); if (err < 0) { check_error(err,"Unable to set stop threshold mode"); return err; } snd_pcm_sw_params_get_stop_threshold(swparams, &bs); #ifdef ALSAMM_DEBUG if(sys_verbose) post("sw_params: set stop_thresh_hold= %d (was %d)", (int) bs,(int)obs); #endif /* AUTOSILENCE: silence if overrun.... */ snd_pcm_sw_params_get_silence_threshold (swparams, &ops); if ((err = snd_pcm_sw_params_set_silence_threshold (handle, swparams, alsamm_period_size)) < 0) { check_error (err,"cannot set silence threshold for"); return -1; } snd_pcm_sw_params_get_silence_threshold (swparams, &ps); #ifdef ALSAMM_DEBUG if(sys_verbose) post("sw_params: set silence_threshold = %d (was %d)", (int) ps,(int)ops); #endif snd_pcm_sw_params_get_silence_size (swparams, &ops); if ((err = snd_pcm_sw_params_set_silence_size(handle, swparams, alsamm_period_size)) < 0) { check_error (err,"cannot set silence size for"); return -1; } snd_pcm_sw_params_get_silence_size (swparams, &ps); #ifdef ALSAMM_DEBUG if(sys_verbose) post("sw_params: set silence_size = %d (was %d)", (int) ps,(int)ops); #endif /* AVAIL: allow the transfer when at least period_size samples can be processed */ snd_pcm_sw_params_get_avail_min(swparams, &ops); err = snd_pcm_sw_params_set_avail_min(handle, swparams, alsamm_transfersize/2); if (err < 0) { check_error(err,"Unable to set avail min for"); return err; } snd_pcm_sw_params_get_avail_min(swparams, &ps); #ifdef ALSAMM_DEBUG if(sys_verbose) post("sw_params: set avail_min= %d (was %d)", (int) ps, (int) ops); #endif /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { check_error(err,"Unable to set sw params"); return err; } #ifdef ALSAMM_DEBUG if(sys_verbose) post("set sw finished"); #endif #else post("alsa: need version 1.0 or above for mmap operation"); #endif /* ALSAAPI9 */ return 0; }