/************************************************************************** * wodPlayer_ProcessMessages [internal] */ static void wodPlayer_ProcessMessages(WINE_WAVEDEV* wwo) { LPWAVEHDR lpWaveHdr; enum win_wm_message msg; DWORD_PTR param; HANDLE ev; int err; while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, ¶m, &ev)) { TRACE("Received %s %lx\n", ALSA_getCmdString(msg), param); switch (msg) { case WINE_WM_PAUSING: if ( snd_pcm_state(wwo->pcm) == SND_PCM_STATE_RUNNING ) { if ( snd_pcm_hw_params_can_pause(wwo->hw_params) ) { err = snd_pcm_pause(wwo->pcm, 1); if ( err < 0 ) ERR("pcm_pause failed: %s\n", snd_strerror(err)); wwo->state = WINE_WS_PAUSED; } else { wodPlayer_Reset(wwo,FALSE); } } SetEvent(ev); break; case WINE_WM_RESTARTING: if (wwo->state == WINE_WS_PAUSED) { if ( snd_pcm_state(wwo->pcm) == SND_PCM_STATE_PAUSED ) { err = snd_pcm_pause(wwo->pcm, 0); if ( err < 0 ) ERR("pcm_pause failed: %s\n", snd_strerror(err)); } wwo->state = WINE_WS_PLAYING; } SetEvent(ev); break; case WINE_WM_HEADER: lpWaveHdr = (LPWAVEHDR)param; /* insert buffer at the end of queue */ { LPWAVEHDR* wh; for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext)); *wh = lpWaveHdr; } if (!wwo->lpPlayPtr) wodPlayer_BeginWaveHdr(wwo,lpWaveHdr); if (wwo->state == WINE_WS_STOPPED) wwo->state = WINE_WS_PLAYING; break; case WINE_WM_RESETTING: wodPlayer_Reset(wwo,TRUE); SetEvent(ev); break; case WINE_WM_BREAKLOOP: if (wwo->state == WINE_WS_PLAYING && wwo->lpLoopPtr != NULL) { /* ensure exit at end of current loop */ wwo->dwLoops = 1; } SetEvent(ev); break; case WINE_WM_CLOSING: /* sanity check: this should not happen since the device must have been reset before */ if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n"); wwo->hThread = 0; wwo->state = WINE_WS_CLOSED; SetEvent(ev); ExitThread(0); /* shouldn't go here */ default: FIXME("unknown message %d\n", msg); break; } } }
/** * Set up the snd_pcm_t object which was opened by the caller. Set up * the configured settings and the audio format. */ static bool alsa_setup(struct alsa_data *ad, struct audio_format *audio_format, GError **error) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; unsigned int sample_rate = audio_format->sample_rate; unsigned int channels = audio_format->channels; snd_pcm_uframes_t alsa_buffer_size; snd_pcm_uframes_t alsa_period_size; int err; const char *cmd = NULL; int retry = MPD_ALSA_RETRY_NR; unsigned int period_time, period_time_ro; unsigned int buffer_time; period_time_ro = period_time = ad->period_time; configure_hw: /* configure HW params */ snd_pcm_hw_params_alloca(&hwparams); cmd = "snd_pcm_hw_params_any"; err = snd_pcm_hw_params_any(ad->pcm, hwparams); if (err < 0) goto error; if (ad->use_mmap) { err = snd_pcm_hw_params_set_access(ad->pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED); if (err < 0) { g_warning("Cannot set mmap'ed mode on ALSA device \"%s\": %s\n", alsa_device(ad), snd_strerror(-err)); g_warning("Falling back to direct write mode\n"); ad->use_mmap = false; } else ad->writei = snd_pcm_mmap_writei; } if (!ad->use_mmap) { cmd = "snd_pcm_hw_params_set_access"; err = snd_pcm_hw_params_set_access(ad->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) goto error; ad->writei = snd_pcm_writei; } err = alsa_output_setup_format(ad->pcm, hwparams, audio_format); if (err < 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support format %s: %s", alsa_device(ad), sample_format_to_string(audio_format->format), snd_strerror(-err)); return false; } err = snd_pcm_hw_params_set_channels_near(ad->pcm, hwparams, &channels); if (err < 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support %i channels: %s", alsa_device(ad), (int)audio_format->channels, snd_strerror(-err)); return false; } audio_format->channels = (int8_t)channels; err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams, &sample_rate, NULL); if (err < 0 || sample_rate == 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support %u Hz audio", alsa_device(ad), audio_format->sample_rate); return false; } audio_format->sample_rate = sample_rate; snd_pcm_uframes_t buffer_size_min, buffer_size_max; snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min); snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size_max); unsigned buffer_time_min, buffer_time_max; snd_pcm_hw_params_get_buffer_time_min(hwparams, &buffer_time_min, 0); snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time_max, 0); g_debug("buffer: size=%u..%u time=%u..%u", (unsigned)buffer_size_min, (unsigned)buffer_size_max, buffer_time_min, buffer_time_max); snd_pcm_uframes_t period_size_min, period_size_max; snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, 0); snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, 0); unsigned period_time_min, period_time_max; snd_pcm_hw_params_get_period_time_min(hwparams, &period_time_min, 0); snd_pcm_hw_params_get_period_time_max(hwparams, &period_time_max, 0); g_debug("period: size=%u..%u time=%u..%u", (unsigned)period_size_min, (unsigned)period_size_max, period_time_min, period_time_max); if (ad->buffer_time > 0) { buffer_time = ad->buffer_time; cmd = "snd_pcm_hw_params_set_buffer_time_near"; err = snd_pcm_hw_params_set_buffer_time_near(ad->pcm, hwparams, &buffer_time, NULL); if (err < 0) goto error; } else { err = snd_pcm_hw_params_get_buffer_time(hwparams, &buffer_time, NULL); if (err < 0) buffer_time = 0; } if (period_time_ro == 0 && buffer_time >= 10000) { period_time_ro = period_time = buffer_time / 4; g_debug("default period_time = buffer_time/4 = %u/4 = %u", buffer_time, period_time); } if (period_time_ro > 0) { period_time = period_time_ro; cmd = "snd_pcm_hw_params_set_period_time_near"; err = snd_pcm_hw_params_set_period_time_near(ad->pcm, hwparams, &period_time, NULL); if (err < 0) goto error; } cmd = "snd_pcm_hw_params"; err = snd_pcm_hw_params(ad->pcm, hwparams); if (err == -EPIPE && --retry > 0 && period_time_ro > 0) { period_time_ro = period_time_ro >> 1; goto configure_hw; } else if (err < 0)
void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, int encoding, float sampleRate, int sampleSizeInBits, int frameSize, int channels, int isSigned, int isBigEndian, int bufferSizeInBytes) { snd_pcm_format_mask_t* formatMask; snd_pcm_format_t format; int dir; int ret = 0; AlsaPcmInfo* info = NULL; /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ snd_pcm_uframes_t alsaPeriodSize = 0; snd_pcm_uframes_t alsaBufferSizeInFrames = 0; TRACE0("> DAUDIO_Open\n"); #ifdef USE_TRACE // for using ALSA debug dump methods if (ALSA_OUTPUT == NULL) { snd_output_stdio_attach(&ALSA_OUTPUT, stdout, 0); } #endif info = (AlsaPcmInfo*) malloc(sizeof(AlsaPcmInfo)); if (!info) { ERROR0("Out of memory\n"); return NULL; } memset(info, 0, sizeof(AlsaPcmInfo)); ret = openPCMfromDeviceID(deviceID, &(info->handle), isSource, FALSE /* do open device*/); if (ret == 0) { // set to blocking mode snd_pcm_nonblock(info->handle, 0); ret = snd_pcm_hw_params_malloc(&(info->hwParams)); if (ret != 0) { ERROR1(" snd_pcm_hw_params_malloc returned error %d\n", ret); } else { ret = -1; if (getAlsaFormatFromFormat(&format, frameSize / channels, sampleSizeInBits, isSigned, isBigEndian, encoding)) { if (setHWParams(info, sampleRate, channels, bufferSizeInBytes / frameSize, format)) { info->frameSize = frameSize; #ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_get_period_size(info->hwParams, &alsaPeriodSize, &dir); info->periodSize = (int) alsaPeriodSize; if (ret < 0) { ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); } snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; #else info->periodSize = snd_pcm_hw_params_get_period_size(info->hwParams, &dir); info->periods = snd_pcm_hw_params_get_periods(info->hwParams, &dir); info->bufferSizeInBytes = snd_pcm_hw_params_get_buffer_size(info->hwParams) * frameSize; ret = 0; #endif TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", (int) info->periodSize, info->periods, info->bufferSizeInBytes); } } } if (ret == 0) { // set software parameters ret = snd_pcm_sw_params_malloc(&(info->swParams)); if (ret != 0) { ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); } else { if (!setSWParams(info)) { ret = -1; } } } if (ret == 0) { // prepare device ret = snd_pcm_prepare(info->handle); if (ret < 0) { ERROR1("ERROR: snd_pcm_prepare: %s\n", snd_strerror(ret)); } } #ifdef GET_POSITION_METHOD2 if (ret == 0) { ret = snd_pcm_status_malloc(&(info->positionStatus)); if (ret != 0) { ERROR1("ERROR in snd_pcm_status_malloc: %s\n", snd_strerror(ret)); } } #endif } if (ret != 0) { DAUDIO_Close((void*) info, isSource); info = NULL; } else { // set to non-blocking mode snd_pcm_nonblock(info->handle, 1); TRACE1("< DAUDIO_Open: Opened device successfully. Handle=%p\n", (void*) info->handle); } return (void*) info; }
//音频采集线程 void * capture_audio_thread(void *para) { int fdsound = 0; int readbyte = 0; #if RECORD_CAPTURE_PCM FILE *fp = fopen("capture.pcm", "wb"); #endif #if SILK_AUDIO_CODEC SKP_uint8 encode[MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES]; #endif #if SILK_AUDIO_CODEC init_silk_encoder();//初始化silk codec printf("end of init silk encoder\n"); #endif #if (SOUND_INTERFACE == SOUND_OSS) fdsound = open("/dev/dsp", O_RDONLY); if(fdsound<0) { perror("以只写方式打开音频设备"); //return; } printf("设置读音频设备参数 setup capture audio device parament\n"); ioctl(fdsound, SNDCTL_DSP_SPEED, &Frequency);//采样频率 ioctl(fdsound, SNDCTL_DSP_SETFMT, &format);//音频设备位宽 ioctl(fdsound, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道 ioctl(fdsound, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区 while(flag_capture_audio) { if((readbyte=read(fdsound, pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short))) < 0) { perror("读声卡数据"); } else { //printf("readbyte=%d\n", readbyte); #if RECORD_CAPTURE_PCM fwrite(pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp); #endif traceprintf("发送信号量 sem_capture\n"); pWriteHeader->FrameNO = FrameNO++; time(&(pWriteHeader->time)); //printf("cNO:%d, readbyte=%d,压缩后大小%d,pWriteHeader->vad=%d\n", pWriteHeader->FrameNO, readbyte, pWriteHeader->count_encode, pWriteHeader->vad); pthread_mutex_lock(&mutex_lock); n++; pWriteHeader->Valid = 1; pthread_mutex_unlock(&mutex_lock); pWriteHeader = pWriteHeader->pNext; sem_post(&sem_capture); } } close(fdsound); #elif (SOUND_INTERFACE == SOUND_ALSA) printf("alsa xxxxxxxxxxxxxxx\n"); struct timeval tv; struct timezone tz; /* Open PCM device for recording (capture). */ rc = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_CAPTURE, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } snd_pcm_hw_params_alloca(¶ms);/* Allocate a hardware parameters object. */ snd_pcm_hw_params_any(handle, params);/* Fill it in with default values. */ /* Set the desired hardware parameters. */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);/* Interleaved mode */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);/* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_channels(handle, params, CHANNELS);/* Two channels (stereo), On for mono */ val = SAMPLERATE; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);/* SAMPLERATE bits/second sampling rate */ frames = SAMPLERATE/1000*READMSFORONCE; snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);/* Set period size to SAMPLES_FOR_EACH_TIME frames. */ /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n",snd_strerror(rc)); exit(1); } snd_pcm_hw_params_get_period_size(params, &frames, &dir);/* Use a buffer large enough to hold one period */ #if 0 size = frames * sizeof(short) * CHANNELS; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); #endif snd_pcm_hw_params_get_period_time(params, &val, &dir);/* We want to loop for 5 seconds */ while(flag_capture_audio) { rc = snd_pcm_readi(handle, pWriteHeader->buffer_capture, frames); printf("read rc=%d\n", rc); if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from read: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short read, read %d frames\n", rc); } #if RECORD_CAPTURE_PCM fwrite(pWriteHeader->buffer_capture, SAMPLERATE/1000*READMSFORONCE*sizeof(short), 1, fp); #endif #if 0 #if DEBUG_SAVE_CAPTURE_PCM rc = fwrite(pWriteHeader->buffer_capture, frames*sizeof(short), 1, fp); if(rc != 1) { fprintf(stderr, "write error %d\n", rc); } #endif #endif #if SILK_AUDIO_CODEC /* max payload size */ int nbBytes = MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES; /* Silk Encoder */ ret = SKP_Silk_SDK_Encode(psEnc, &encControl, pWriteHeader->buffer_capture, (SKP_int16)SAMPLERATE/1000*READMSFORONCE, pWriteHeader->buffer_encode, &nbBytes); pWriteHeader->count = nbBytes; printf("ret=%d, nbBytes=%d\n", ret, nbBytes); if(ret) { printf( "SKP_Silk_Encode returned %d, nbBytes=%d\n", ret, nbBytes); //break; } #endif #if SPEEX_AUDIO_CODEC speex_bits_reset(&bits); /*Encode the frame*/ speex_encode_int(state, pWriteHeader->buffer_capture, &bits); /*Copy the bits to an array of char that can be written*/ nbBytes = speex_bits_write(&bits, cbits, 200); printf("压缩后大小 %d\n", nbBytes); #endif sem_post(&sem_capture); sem_post(&sem_capture); gettimeofday(&tv, &tz); //((AUDIOBUFFER*)(pWriteHeader->buffer_capture))->FrameNO = FrameNO++; //((AUDIOBUFFER*)(pWriteHeader->buffer))->sec = tv.tv_sec; //((AUDIOBUFFER*)(pWriteHeader->buffer))->usec = tv.tv_usec; //printf("capture NO=%5d \n", FrameNO); pthread_mutex_lock(&mutex_lock); //pWriteHeader = pWriteHeader->pNext; pWriteHeader->Valid = 1; n++; pthread_mutex_unlock(&mutex_lock); pWriteHeader = pWriteHeader->pNext; sem_post(&sem_capture); //traceprintf("发送信号量 sem_capture\n"); } snd_pcm_drain(handle); snd_pcm_close(handle); #if 0 free(buffer); #endif #endif #if RECORD_CAPTURE_PCM fclose(fp); #endif printf("音频采集线程已经关闭 audio capture thread is closed\n"); return NULL; }
int alsa_hook_hw_params(alsa_hook_t alsa_hook, snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { struct alsa_hook_stream_s *stream; snd_pcm_format_t format; snd_pcm_uframes_t period_size; snd_pcm_access_t access; int dir, ret; alsa_hook_get_stream(alsa_hook, pcm, &stream); if (unlikely((ret = alsa_hook_lock_write(alsa_hook, stream)))) return ret; glc_log(alsa_hook->glc, GLC_DEBUG, "alsa_hook", "%p: creating/updating configuration for stream %d", stream->pcm, stream->id); /* extract information */ if (unlikely((ret = snd_pcm_hw_params_get_format(params, &format)) < 0)) goto err; stream->flags = 0; /* zero flags */ stream->format = pcm_fmt_to_glc_fmt(format); if (unlikely(!stream->format)) { glc_log(alsa_hook->glc, GLC_ERROR, "alsa_hook", "%p: unsupported audio format 0x%02x", stream->pcm, format); ret = ENOTSUP; goto err; } if (unlikely((ret = snd_pcm_hw_params_get_rate(params, &stream->rate, &dir)) < 0)) goto err; if (unlikely((ret = snd_pcm_hw_params_get_channels(params, &stream->channels)) < 0)) goto err; if (unlikely((ret = snd_pcm_hw_params_get_period_size(params, &period_size, NULL)) < 0)) goto err; if (unlikely((ret = snd_pcm_hw_params_get_access(params, &access)) < 0)) goto err; if ((access == SND_PCM_ACCESS_RW_INTERLEAVED) || (access == SND_PCM_ACCESS_MMAP_INTERLEAVED)) stream->flags |= GLC_AUDIO_INTERLEAVED; else if (access == SND_PCM_ACCESS_MMAP_COMPLEX) { stream->flags |= GLC_AUDIO_INTERLEAVED; /* convert to interleaved */ stream->complex = 1; /* do conversion */ } else { glc_log(alsa_hook->glc, GLC_ERROR, "alsa_hook", "%p: unsupported access mode 0x%02x", stream->pcm, access); ret = ENOTSUP; goto err; } glc_log(alsa_hook->glc, GLC_DEBUG, "alsa_hook", "%p: %d channels, rate %d, flags 0x%02x", stream->pcm, stream->channels, stream->rate, stream->flags); stream->fmt = 1; if (alsa_hook->started) { if (unlikely((ret = alsa_hook_stream_init(alsa_hook, stream)))) goto err; } alsa_hook_unlock_write(alsa_hook, stream); return 0; err: glc_log(alsa_hook->glc, GLC_ERROR, "alsa_hook", "%p: can't extract hardware configuration: %s (%d)", stream->pcm, snd_strerror(ret), ret); alsa_hook_unlock_write(alsa_hook, stream); return ret; }
int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) { unsigned int rrate; int err, dir; printf("set_hwparams\n"); /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return err; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, access); if (err < 0) { printf("Access type not available for playback: %s\n", snd_strerror(err)); return err; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, format); if (err < 0) { printf("Sample format not available for playback: %s\n", snd_strerror(err)); return err; } /* set the count of channels */ err = snd_pcm_hw_params_set_channels(handle, params, channels); if (err < 0) { printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); return err; } /* set the stream rate */ rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); if (err < 0) { printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return err; } if (rrate != rate) { printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); return -EINVAL; } dir = 0; err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, &dir); if (err < 0) { printf("Unable to set period size %i for playback: %s\n", (int)period_size, snd_strerror(err)); return err; } err = snd_pcm_hw_params_set_periods(handle, params, periods, 0); if (err < 0) { printf("Unable to set periods %i for playback: %s\n", periods, snd_strerror(err)); return err; } /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_periods(params, &periods, &dir); if (err < 0) { printf("Unable to get periods for playback: %s\n", snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_period_size(params, &period_size, &dir); if (err < 0) { printf("Unable to get period size for playback: %s\n", snd_strerror(err)); return err; } return 0; }
void* PORT_Open(INT32 mixerIndex) { char devname[16]; snd_mixer_t* mixer_handle; int err; PortMixer* handle; TRACE0("> PORT_Open\n"); sprintf(devname, ALSA_HARDWARE_CARD, (int) mixerIndex); if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) { ERROR2("Mixer %s open error: %s", devname, snd_strerror(err)); return NULL; } if ((err = snd_mixer_attach(mixer_handle, devname)) < 0) { ERROR2("Mixer attach %s error: %s", devname, snd_strerror(err)); snd_mixer_close(mixer_handle); return NULL; } if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0) { ERROR1("Mixer register error: %s", snd_strerror(err)); snd_mixer_close(mixer_handle); return NULL; } err = snd_mixer_load(mixer_handle); if (err < 0) { ERROR2("Mixer %s load error: %s", devname, snd_strerror(err)); snd_mixer_close(mixer_handle); return NULL; } handle = (PortMixer*) calloc(1, sizeof(PortMixer)); if (handle == NULL) { ERROR0("malloc() failed."); snd_mixer_close(mixer_handle); return NULL; } handle->numElems = 0; handle->elems = (snd_mixer_elem_t**) calloc(MAX_ELEMS, sizeof(snd_mixer_elem_t*)); if (handle->elems == NULL) { ERROR0("malloc() failed."); snd_mixer_close(mixer_handle); free(handle); return NULL; } handle->types = (INT32*) calloc(MAX_ELEMS, sizeof(INT32)); if (handle->types == NULL) { ERROR0("malloc() failed."); snd_mixer_close(mixer_handle); free(handle->elems); free(handle); return NULL; } handle->controls = (PortControl*) calloc(MAX_CONTROLS, sizeof(PortControl)); if (handle->controls == NULL) { ERROR0("malloc() failed."); snd_mixer_close(mixer_handle); free(handle->elems); free(handle->types); free(handle); return NULL; } handle->mixer_handle = mixer_handle; // necessary to initialize data structures PORT_GetPortCount(handle); TRACE0("< PORT_Open\n"); return handle; }
/******************************************************************************* ** ** Function app_alsa_capture_loopback_open ** ** Description Open ALSA Capture channel (from loopback driver) ** ** Parameters p_open: Capture parameters ** ** Returns status ** *******************************************************************************/ int app_alsa_capture_loopback_open(tAPP_ALSA_CAPTURE_OPEN *p_open) { int mode = 0; /* Default is blocking */ unsigned int nb_channels; int rv; snd_pcm_format_t format; snd_pcm_access_t access; APP_DEBUG0("Opening ALSA/Asound audio driver Capture"); /* Sanity check if already opened */ if (app_alsa_cb.p_capture_handle != NULL) { APP_DEBUG0("Capture was already opened"); } /* check PCM Format parameter */ format = app_alsa_get_pcm_format(p_open->format); if (format == SND_PCM_FORMAT_UNKNOWN) { return -1; } /* Check PCM access parameter */ if (p_open->access == APP_ALSA_PCM_ACCESS_RW_INTERLEAVED) { access = SND_PCM_ACCESS_RW_INTERLEAVED; } else { APP_ERROR1("Unsupported PCM access:%d", p_open->access); return -1; } /* Check Blocking parameter */ if (p_open->blocking == FALSE) { mode = SND_PCM_NONBLOCK; } /* check Stereo parameter */ if (p_open->stereo) { nb_channels = 2; } else { nb_channels = 1; } /* Save the Capture open parameters */ memcpy(&app_alsa_cb.capture_param, p_open, sizeof(app_alsa_cb.capture_param)); /* Open ALSA driver */ rv = snd_pcm_open(&app_alsa_cb.p_capture_handle, alsa_device_loopback, SND_PCM_STREAM_CAPTURE, mode); if (rv < 0) { APP_ERROR1("unable to open ALSA loopback device in Capture mode:%s", snd_strerror(rv)); return rv; } APP_DEBUG0("ALSA loopback driver opened in Capture mode"); /* Configure ALSA driver with PCM parameters */ rv = snd_pcm_set_params(app_alsa_cb.p_capture_handle, format, access, nb_channels, p_open->sample_rate, 1, /* SW resample */ p_open->latency); if (rv) { APP_ERROR1("Unable to config ALSA device:%s", snd_strerror(rv)); snd_pcm_close(app_alsa_cb.p_capture_handle); app_alsa_cb.p_capture_handle = NULL; return rv; } return 0; }
int main(int argc, char **argv) { register int err; int cardNum; // Start with first card cardNum = -1; for (;;) { snd_ctl_t *cardHandle; // Get next sound card's card number. When "cardNum" == -1, then ALSA // fetches the first card if ((err = snd_card_next(&cardNum)) < 0) { printf("Can't get the next card number: %s\n", snd_strerror(err)); break; } // No more cards? ALSA sets "cardNum" to -1 if so if (cardNum < 0) break; // Open this card's control interface. We specify only the card number -- not // any device nor sub-device too { char str[64]; sprintf(str, "hw:%i", cardNum); if ((err = snd_ctl_open(&cardHandle, str, 0)) < 0) { printf("Can't open card %i: %s\n", cardNum, snd_strerror(err)); continue; } } { int devNum, totalDevices; // No waveform devices found yet totalDevices = 0; // Start with the first wave device on this card devNum = -1; for (;;) { // Get the number of the next wave device on this card if ((err = snd_ctl_pcm_next_device(cardHandle, &devNum)) < 0) { printf("Can't get next wave device number: %s\n", snd_strerror(err)); break; } // No more wave devices on this card? ALSA sets "devNum" to -1 if so. // NOTE: It's possible that this sound card may have no wave devices on it // at all, for example if it's only a MIDI card if (devNum < 0) break; // Another wave device found on this card, so bump the count ++totalDevices; } printf("Found %i digital audio devices on card %i\n", totalDevices, cardNum); } // Close the card's control interface after we're done with it snd_ctl_close(cardHandle); } // ALSA allocates some mem to load its config file when we call some of the // above functions. Now that we're done getting the info, let's tell ALSA // to unload the info and free up that mem snd_config_update_free_global(); }
static int mixer_open(void) { snd_mixer_elem_t *elem; snd_mixer_elem_t *master; snd_mixer_elem_t *pcm; snd_mixer_elem_t *custom; snd_mixer_selem_id_t *sid; int ret; ret = snd_mixer_open(&mixer_hdl, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Failed to open mixer: %s\n", snd_strerror(ret)); mixer_hdl = NULL; return -1; } ret = snd_mixer_attach(mixer_hdl, card_name); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Failed to attach mixer: %s\n", snd_strerror(ret)); goto out_close; } ret = snd_mixer_selem_register(mixer_hdl, NULL, NULL); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Failed to register mixer: %s\n", snd_strerror(ret)); goto out_detach; } ret = snd_mixer_load(mixer_hdl); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Failed to load mixer: %s\n", snd_strerror(ret)); goto out_detach; } /* Grab interesting elements */ snd_mixer_selem_id_alloca(&sid); pcm = NULL; master = NULL; custom = NULL; for (elem = snd_mixer_first_elem(mixer_hdl); elem; elem = snd_mixer_elem_next(elem)) { snd_mixer_selem_get_id(elem, sid); if (mixer_name && (strcmp(snd_mixer_selem_id_get_name(sid), mixer_name) == 0)) { custom = elem; break; } else if (strcmp(snd_mixer_selem_id_get_name(sid), "PCM") == 0) pcm = elem; else if (strcmp(snd_mixer_selem_id_get_name(sid), "Master") == 0) master = elem; } if (mixer_name) { if (custom) vol_elem = custom; else { DPRINTF(E_LOG, L_LAUDIO, "Failed to open configured mixer element '%s'\n", mixer_name); goto out_detach; } } else if (pcm) vol_elem = pcm; else if (master) vol_elem = master; else { DPRINTF(E_LOG, L_LAUDIO, "Failed to open PCM or Master mixer element\n"); goto out_detach; } /* Get min & max volume */ snd_mixer_selem_get_playback_volume_range(vol_elem, &vol_min, &vol_max); return 0; out_detach: snd_mixer_detach(mixer_hdl, card_name); out_close: snd_mixer_close(mixer_hdl); mixer_hdl = NULL; vol_elem = NULL; return -1; }
static int laudio_alsa_open(void) { snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t bufsize; snd_pcm_uframes_t period_size; int ret; hw_params = NULL; ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret)); return -1; } /* HW params */ ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_any(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret)); goto out_fail; } // With a small period size we seem to get underruns because the period time // passes before we manage to feed with samples (if the player is slightly // behind - especially critical during startup when the buffer is low) // Internet suggests period_size should be /2 bufsize, but default seems to be // much lower, so compromise on /4 (but not more than 65536 frames = almost 2 sec). period_size = bufsize / 4; if (period_size > 65536) period_size = 65536; ret = snd_pcm_hw_params_set_period_size_near(hdl, hw_params, &period_size, NULL); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set period size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples, period size is %lu samples\n", bufsize, period_size); ret = snd_pcm_hw_params(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); goto out_fail; } snd_pcm_hw_params_free(hw_params); hw_params = NULL; pcm_pos = 0; pcm_last_error = 0; pcm_recovery = 0; pcm_buf_threshold = ((bufsize - period_size) / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; pcm_period_size = period_size; ret = mixer_open(); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n"); goto out_fail; } update_status(LAUDIO_OPEN); return 0; out_fail: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(hdl); hdl = NULL; return -1; }
static int laudio_alsa_start(uint64_t cur_pos, uint64_t next_pkt) { snd_output_t *output; char *debug_pcm_cfg; int ret; ret = snd_pcm_prepare(hdl); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not prepare PCM device: %s\n", snd_strerror(ret)); return -1; } DPRINTF(E_DBG, L_LAUDIO, "Start local audio curpos %" PRIu64 ", next_pkt %" PRIu64 "\n", cur_pos, next_pkt); /* Make pcm_pos the rtptime of the packet containing cur_pos */ pcm_pos = next_pkt; while (pcm_pos > cur_pos) pcm_pos -= AIRTUNES_V2_PACKET_SAMPLES; pcm_start_pos = next_pkt + pcm_period_size; /* Compensate period size, otherwise get_pos won't be correct */ pcm_pos += pcm_period_size; DPRINTF(E_DBG, L_LAUDIO, "PCM pos %" PRIu64 ", start pos %" PRIu64 "\n", pcm_pos, pcm_start_pos); pcm_pkt_head = NULL; pcm_pkt_tail = NULL; pcm_last_error = 0; pcm_recovery = 0; // alsa doesn't actually seem to wait for this threshold? ret = laudio_alsa_set_start_threshold(pcm_buf_threshold); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set PCM start threshold for local audio start\n"); return -1; } // Dump PCM config data for E_DBG logging ret = snd_output_buffer_open(&output); if (ret == 0) { if (snd_pcm_dump_setup(hdl, output) == 0) { snd_output_buffer_string(output, &debug_pcm_cfg); DPRINTF(E_DBG, L_LAUDIO, "Dump of sound device config:\n%s\n", debug_pcm_cfg); } snd_output_close(output); } update_status(LAUDIO_STARTED); return 0; }
static void laudio_alsa_write(uint8_t *buf, uint64_t rtptime) { struct pcm_packet *pkt; snd_pcm_sframes_t nsamp; int ret; pkt = (struct pcm_packet *)malloc(sizeof(struct pcm_packet)); if (!pkt) { DPRINTF(E_LOG, L_LAUDIO, "Out of memory for PCM pkt\n"); update_status(LAUDIO_FAILED); return; } memcpy(pkt->samples, buf, sizeof(pkt->samples)); pkt->rtptime = rtptime; pkt->offset = 0; pkt->next = NULL; if (pcm_pkt_tail) { pcm_pkt_tail->next = pkt; pcm_pkt_tail = pkt; } else { pcm_pkt_head = pkt; pcm_pkt_tail = pkt; } if (pcm_pos < pcm_pkt_head->rtptime) { pcm_pos += AIRTUNES_V2_PACKET_SAMPLES; return; } else if ((pcm_status != LAUDIO_RUNNING) && (pcm_pos >= pcm_start_pos)) { update_status(LAUDIO_RUNNING); } pkt = pcm_pkt_head; while (pkt) { if (pcm_recovery) { ret = laudio_alsa_xrun_recover(0); if ((ret == 2) && (pcm_recovery < 10)) return; else { if (ret == 2) DPRINTF(E_LOG, L_LAUDIO, "Couldn't recover PCM device after 10 tries, aborting\n"); update_status(LAUDIO_FAILED); return; } } nsamp = snd_pcm_writei(hdl, pkt->samples + pkt->offset, BTOS(sizeof(pkt->samples) - pkt->offset)); if ((nsamp == -EPIPE) || (nsamp == -ESTRPIPE)) { ret = laudio_alsa_xrun_recover(nsamp); if ((ret < 0) || (ret == 1)) { if (ret < 0) DPRINTF(E_LOG, L_LAUDIO, "PCM write error: %s\n", snd_strerror(ret)); update_status(LAUDIO_FAILED); return; } else if (ret != 0) return; continue; } else if (nsamp < 0) { DPRINTF(E_LOG, L_LAUDIO, "PCM write error: %s\n", snd_strerror(nsamp)); update_status(LAUDIO_FAILED); return; } pcm_last_error = 0; pcm_pos += nsamp; pkt->offset += STOB(nsamp); if (pkt->offset == sizeof(pkt->samples)) { pcm_pkt_head = pkt->next; if (pkt == pcm_pkt_tail) pcm_pkt_tail = NULL; free(pkt); pkt = pcm_pkt_head; } /* Don't let ALSA fill up the buffer too much */ if (nsamp == AIRTUNES_V2_PACKET_SAMPLES) return; } }
/************************************************************************** * wodOpen [internal] */ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) { WINE_WAVEDEV* wwo; snd_pcm_t * pcm = NULL; snd_hctl_t * hctl = NULL; snd_pcm_hw_params_t * hw_params = NULL; snd_pcm_sw_params_t * sw_params; snd_pcm_access_t access; snd_pcm_format_t format = -1; unsigned int rate; unsigned int buffer_time = 120000; unsigned int period_time = 22000; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; int flags; int err=0; int dir=0; DWORD retcode = 0; TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= ALSA_WodNumDevs) { TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs); return MMSYSERR_BADDEVICEID; } /* only PCM format is supported so far... */ if (!ALSA_supportedFormat(lpDesc->lpFormat)) { WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return WAVERR_BADFORMAT; } if (dwFlags & WAVE_FORMAT_QUERY) { TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return MMSYSERR_NOERROR; } wwo = &WOutDev[wDevID]; if (wwo->pcm != NULL) { WARN("%d already allocated\n", wDevID); return MMSYSERR_ALLOCATED; } if (dwFlags & WAVE_DIRECTSOUND) FIXME("Why are we called with DirectSound flag? It doesn't use MMSYSTEM any more\n"); /* not supported, ignore it */ dwFlags &= ~WAVE_DIRECTSOUND; flags = SND_PCM_NONBLOCK; if ( (err = snd_pcm_open(&pcm, wwo->pcmname, SND_PCM_STREAM_PLAYBACK, flags)) < 0) { ERR("Error open: %s\n", snd_strerror(err)); return MMSYSERR_NOTENABLED; } if (wwo->ctlname) { err = snd_hctl_open(&hctl, wwo->ctlname, 0); if (err >= 0) { snd_hctl_load(hctl); } else { WARN("Could not open hctl for [%s]: %s\n", wwo->ctlname, snd_strerror(err)); hctl = NULL; } } wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); wwo->waveDesc = *lpDesc; ALSA_copyFormat(lpDesc->lpFormat, &wwo->format); TRACE("Requested this format: %dx%dx%d %s\n", wwo->format.Format.nSamplesPerSec, wwo->format.Format.wBitsPerSample, wwo->format.Format.nChannels, ALSA_getFormat(wwo->format.Format.wFormatTag)); if (wwo->format.Format.wBitsPerSample == 0) { WARN("Resetting zeroed wBitsPerSample\n"); wwo->format.Format.wBitsPerSample = 8 * (wwo->format.Format.nAvgBytesPerSec / wwo->format.Format.nSamplesPerSec) / wwo->format.Format.nChannels; } #define EXIT_ON_ERROR(f,e,txt) do \ { \ int err; \ if ( (err = (f) ) < 0) \ { \ WARN(txt ": %s\n", snd_strerror(err)); \ retcode=e; \ goto errexit; \ } \ } while(0) sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() ); snd_pcm_hw_params_malloc(&hw_params); if (! hw_params) { retcode = MMSYSERR_NOMEM; goto errexit; } snd_pcm_hw_params_any(pcm, hw_params); access = SND_PCM_ACCESS_MMAP_INTERLEAVED; if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) { WARN("mmap not available. switching to standard write.\n"); access = SND_PCM_ACCESS_RW_INTERLEAVED; EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback"); wwo->write = snd_pcm_writei; } else wwo->write = snd_pcm_mmap_writei; if ((err = snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels)) < 0) { WARN("unable to set required channels: %d\n", wwo->format.Format.nChannels); EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels ), WAVERR_BADFORMAT, "unable to set required channels" ); } if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) || ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) { format = (wwo->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 : (wwo->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : (wwo->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE : (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1; } else if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ format = (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1; } else { ERR("invalid format: %0x04x\n", wwo->format.Format.wFormatTag); retcode = WAVERR_BADFORMAT; goto errexit; } if ((err = snd_pcm_hw_params_set_format(pcm, hw_params, format)) < 0) { WARN("unable to set required format: %s\n", snd_pcm_format_name(format)); EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format" ); } rate = wwo->format.Format.nSamplesPerSec; dir=0; err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir); if (err < 0) { WARN("Rate %d Hz not available for playback: %s\n", wwo->format.Format.nSamplesPerSec, snd_strerror(rate)); retcode = WAVERR_BADFORMAT; goto errexit; } if (!ALSA_NearMatch(rate, wwo->format.Format.nSamplesPerSec)) { WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate); retcode = WAVERR_BADFORMAT; goto errexit; } TRACE("Got this format: %dx%dx%d %s\n", wwo->format.Format.nSamplesPerSec, wwo->format.Format.wBitsPerSample, wwo->format.Format.nChannels, ALSA_getFormat(wwo->format.Format.wFormatTag)); dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time"); dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time"); EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback"); err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir); err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); snd_pcm_sw_params_current(pcm, sw_params); EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size"); EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback"); #undef EXIT_ON_ERROR snd_pcm_prepare(pcm); if (TRACE_ON(wave)) ALSA_TraceParameters(hw_params, sw_params, FALSE); /* now, we can save all required data for later use... */ wwo->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size); wwo->lpQueuePtr = wwo->lpPlayPtr = wwo->lpLoopPtr = NULL; wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0; wwo->dwPartialOffset = 0; ALSA_InitRingMessage(&wwo->msgRing); wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL); wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwo->dwThreadID)); if (wwo->hThread) SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL); else { ERR("Thread creation for the wodPlayer failed!\n"); CloseHandle(wwo->hStartUpEvent); retcode = MMSYSERR_NOMEM; goto errexit; } WaitForSingleObject(wwo->hStartUpEvent, INFINITE); CloseHandle(wwo->hStartUpEvent); wwo->hStartUpEvent = INVALID_HANDLE_VALUE; TRACE("handle=%p\n", pcm); TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n", wwo->format.Format.wBitsPerSample, wwo->format.Format.nAvgBytesPerSec, wwo->format.Format.nSamplesPerSec, wwo->format.Format.nChannels, wwo->format.Format.nBlockAlign); HeapFree( GetProcessHeap(), 0, sw_params ); wwo->pcm = pcm; wwo->hctl = hctl; if ( wwo->hw_params ) snd_pcm_hw_params_free(wwo->hw_params); wwo->hw_params = hw_params; return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L); errexit: if (pcm) snd_pcm_close(pcm); if (hctl) { snd_hctl_free(hctl); snd_hctl_close(hctl); } if ( hw_params ) snd_pcm_hw_params_free(hw_params); HeapFree( GetProcessHeap(), 0, sw_params ); if (wwo->msgRing.ring_buffer_size > 0) ALSA_DestroyRingMessage(&wwo->msgRing); return retcode; }
/* open & setup audio device return: 1=success 0=fail */ static int init(int rate_hz, int channels, int format, int flags) { int err; int block; strarg_t device; snd_pcm_uframes_t bufsize; snd_pcm_uframes_t boundary; opt_t subopts[] = { {"block", OPT_ARG_BOOL, &block, NULL}, {"device", OPT_ARG_STR, &device, (opt_test_f)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; #ifndef WORDS_BIGENDIAN case AF_FORMAT_AC3: #endif case AF_FORMAT_S16_LE: alsa_format = SND_PCM_FORMAT_S16_LE; break; #ifdef WORDS_BIGENDIAN case AF_FORMAT_AC3: #endif case AF_FORMAT_S16_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_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 (format == AF_FORMAT_AC3) { device.str = "iec958"; mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %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; 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; } ao_noblock = !block; parse_device(alsa_device, device.str, device.len); mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device); //setting modes for block or nonblock-mode if (ao_noblock) { open_mode = SND_PCM_NONBLOCK; } else { open_mode = 0; } //sets buff/chunksize if its set manually if (ao_data.buffersize) { switch (ao_data.buffersize) { case 1: alsa_fragcount = 16; chunk_size = 512; mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n"); mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n"); break; case 2: alsa_fragcount = 8; chunk_size = 1024; mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n"); mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n"); break; case 3: alsa_fragcount = 32; chunk_size = 512; mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n"); mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n"); break; case 4: alsa_fragcount = 16; chunk_size = 1024; mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n"); mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n"); break; default: alsa_fragcount = 16; chunk_size = 1024; break; } } if (!alsa_handler) { //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC if ((err = try_open_device(alsa_device, open_mode, format == AF_FORMAT_AC3)) < 0) { if (err != -EBUSY && ao_noblock) { mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed); if ((err = try_open_device(alsa_device, 0, format == AF_FORMAT_AC3)) < 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: pcm opened 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; 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 */ #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 = snd_pcm_format_physical_width(alsa_format) / 8; bytes_per_sample *= ao_data.channels; ao_data.bps = ao_data.samplerate * bytes_per_sample; #ifdef BUFFERTIME { int alsa_buffer_time = 500000; /* original 60 */ int alsa_period_time; alsa_period_time = alsa_buffer_time/4; 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); } else alsa_buffer_time = err; if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, &alsa_period_time, NULL)) < 0) /* original: alsa_buffer_time/ao_data.bps */ { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriodTime, snd_strerror(err)); return 0; } mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_BufferTimePeriodTime, alsa_buffer_time, err); } #endif//end SET_BUFFERTIME #ifdef SET_CHUNKSIZE { //set chunksize if ((err = snd_pcm_hw_params_set_period_size_near(alsa_handler, alsa_hwparams, &chunk_size, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriodSize, chunk_size, snd_strerror(err)); return 0; } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set to %li\n", chunk_size); } 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; } else { mp_msg(MSGT_AO,MSGL_V,"alsa-init: fragcount=%i\n", alsa_fragcount); } } #endif//end SET_CHUNKSIZE /* 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, 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 void *alsa_qsa_init(const char *device, unsigned rate, unsigned latency) { int err, card, dev, i; snd_pcm_channel_params_t params = {0}; snd_pcm_channel_info_t pi; snd_pcm_channel_setup_t setup = {0}; settings_t *settings = config_get_ptr(); alsa_t *alsa = (alsa_t*)calloc(1, sizeof(alsa_t)); if (!alsa) return NULL; (void)device; (void)rate; (void)latency; if ((err = snd_pcm_open_preferred(&alsa->pcm, &card, &dev, SND_PCM_OPEN_PLAYBACK)) < 0) { RARCH_ERR("[ALSA QSA]: Audio open error: %s\n", snd_strerror(err)); goto error; } if((err = snd_pcm_nonblock_mode(alsa->pcm, 1)) < 0) { RARCH_ERR("[ALSA QSA]: Can't set blocking mode: %s\n", snd_strerror(err)); goto error; } memset(&pi, 0, sizeof(pi)); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((err = snd_pcm_channel_info(alsa->pcm, &pi)) < 0) { RARCH_ERR("[ALSA QSA]: snd_pcm_channel_info failed: %s\n", snd_strerror(err)); goto error; } memset(¶ms, 0, sizeof(params)); params.channel = SND_PCM_CHANNEL_PLAYBACK; params.mode = SND_PCM_MODE_BLOCK; params.format.interleave = 1; params.format.format = SND_PCM_SFMT_S16_LE; params.format.rate = DEFAULT_RATE; params.format.voices = 2; params.start_mode = SND_PCM_START_FULL; params.stop_mode = SND_PCM_STOP_STOP; params.buf.block.frag_size = pi.max_fragment_size; params.buf.block.frags_min = 2; params.buf.block.frags_max = 8; RARCH_LOG("Fragment size: %d\n", params.buf.block.frag_size); RARCH_LOG("Min Fragment size: %d\n", params.buf.block.frags_min); RARCH_LOG("Max Fragment size: %d\n", params.buf.block.frags_max); if ((err = snd_pcm_channel_params(alsa->pcm, ¶ms)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Parameter Error: %s\n", snd_strerror(err)); goto error; } setup.channel = SND_PCM_CHANNEL_PLAYBACK; if ((err = snd_pcm_channel_setup(alsa->pcm, &setup)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Parameter Read Back Error: %s\n", snd_strerror(err)); goto error; } if (settings->audio.block_frames) alsa->buf_size = settings->audio.block_frames * 4; else alsa->buf_size = next_pow2(32 * latency); RARCH_LOG("[ALSA QSA]: buffer size: %u bytes\n", alsa->buf_size); alsa->buf_count = (latency * 4 * rate + 500) / 1000; alsa->buf_count = (alsa->buf_count + alsa->buf_size / 2) / alsa->buf_size; if ((err = snd_pcm_channel_prepare(alsa->pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Prepare Error: %s\n", snd_strerror(err)); goto error; } alsa->buffer = (uint8_t**)calloc(sizeof(uint8_t*), alsa->buf_count); if (!alsa->buffer) goto error; alsa->buffer_chunk = (uint8_t*)calloc(alsa->buf_count, alsa->buf_size); if (!alsa->buffer_chunk) goto error; for (i = 0; i < alsa->buf_count; i++) alsa->buffer[i] = alsa->buffer_chunk + i * alsa->buf_size; alsa->has_float = false; alsa->can_pause = true; RARCH_LOG("[ALSA QSA]: Can pause: %s.\n", alsa->can_pause ? "yes" : "no"); return alsa; error: return (void*)-1; }
/* to set/get/query special features/parameters */ static int control(int cmd, void *arg) { switch(cmd) { case AOCONTROL_QUERY_FORMAT: return CONTROL_TRUE; case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: { ao_control_vol_t *vol = (ao_control_vol_t *)arg; int err; snd_mixer_t *handle; snd_mixer_elem_t *elem; snd_mixer_selem_id_t *sid; static char *mix_name = "PCM"; static char *card = "default"; static int mix_index = 0; long pmin, pmax; long get_vol, set_vol; float f_multi; if(mixer_channel) { char *test_mix_index; mix_name = strdup(mixer_channel); if ((test_mix_index = strchr(mix_name, ','))){ *test_mix_index = 0; test_mix_index++; mix_index = strtol(test_mix_index, &test_mix_index, 0); if (*test_mix_index){ mp_msg(MSGT_AO,MSGL_ERR, MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero); mix_index = 0 ; } } } if(mixer_device) card = mixer_device; if(ao_data.format == AF_FORMAT_AC3) return CONTROL_TRUE; //allocate simple id snd_mixer_selem_id_alloca(&sid); //sets simple-mixer index and name snd_mixer_selem_id_set_index(sid, mix_index); snd_mixer_selem_id_set_name(sid, mix_name); if (mixer_channel) { free(mix_name); mix_name = NULL; } if ((err = snd_mixer_open(&handle, 0)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerOpenError, snd_strerror(err)); return CONTROL_ERROR; } if ((err = snd_mixer_attach(handle, card)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerAttachError, card, snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerRegisterError, snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } err = snd_mixer_load(handle); if (err < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerLoadError, snd_strerror(err)); snd_mixer_close(handle); return CONTROL_ERROR; } elem = snd_mixer_find_selem(handle, sid); if (!elem) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToFindSimpleControl, snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); snd_mixer_close(handle); return CONTROL_ERROR; } snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax); f_multi = (100 / (float)(pmax - pmin)); if (cmd == AOCONTROL_SET_VOLUME) { set_vol = vol->left / f_multi + pmin + 0.5; //setting channels if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingLeftChannel, snd_strerror(err)); return CONTROL_ERROR; } mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol); set_vol = vol->right / f_multi + pmin + 0.5; if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) { mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingRightChannel, snd_strerror(err)); return CONTROL_ERROR; } mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n", set_vol, pmin, pmax, f_multi); if (snd_mixer_selem_has_playback_switch(elem)) { int lmute = (vol->left == 0.0); int rmute = (vol->right == 0.0); if (snd_mixer_selem_has_playback_switch_joined(elem)) { lmute = rmute = lmute && rmute; } else { snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, !rmute); } snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, !lmute); } } else { snd_mixer_selem_get_playback_volume(elem, 0, &get_vol); vol->left = (get_vol - pmin) * f_multi; snd_mixer_selem_get_playback_volume(elem, 1, &get_vol); vol->right = (get_vol - pmin) * f_multi; mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right); } snd_mixer_close(handle); return CONTROL_OK; } } //end switch return(CONTROL_UNKNOWN); }
void CAESinkALSA::HandleError(const char* name, int err) { switch(err) { case -EPIPE: CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - underrun", name); if ((err = snd_pcm_prepare(m_pcm)) < 0) CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err)); break; case -ESTRPIPE: CLog::Log(LOGINFO, "CAESinkALSA::HandleError(%s) - Resuming after suspend", name); /* try to resume the stream */ while((err = snd_pcm_resume(m_pcm)) == -EAGAIN) Sleep(1); /* if the hardware doesnt support resume, prepare the stream */ if (err == -ENOSYS) if ((err = snd_pcm_prepare(m_pcm)) < 0) CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err)); break; default: CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_writei returned %d (%s)", name, err, snd_strerror(err)); break; } }
static int alsa_init(const char *param, int *speed, int *fragsize, int *fragnr, int *channels) { int err, dir; unsigned int rate, periods; snd_pcm_uframes_t period_size; snd_pcm_hw_params_t *hwparams; if (!param) { param = "default"; } snd_pcm_hw_params_alloca(&hwparams); if ((err = snd_pcm_open(&handle, param, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { log_message(LOG_DEFAULT, "Playback open error for '%s': %s", param, snd_strerror(err)); return 1; } if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) { log_message(LOG_DEFAULT, "Broken configuration for playback: no configurations available: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { log_message(LOG_DEFAULT, "Access type not available for playback: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16)) < 0) { log_message(LOG_DEFAULT, "Sample format not available for playback: %s", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_channels(handle, hwparams, *channels)) < 0) { log_message(LOG_DEFAULT, "Channels count (%i) not available for playbacks: %s", *channels, snd_strerror(err)); goto fail; } rate = (unsigned int)*speed; if ((err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0)) < 0) { log_message(LOG_DEFAULT, "Rate %iHz not available for playback: %s", *speed, snd_strerror(err)); goto fail; } if (rate != (unsigned int)*speed) { printf("Rate doesn't match (requested %iHz, got %iHz)", *speed, rate); *speed = rate; } period_size = *fragsize; dir = 0; if ((err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &dir)) < 0) { log_message(LOG_DEFAULT, "Unable to set period size %li for playback: %s", period_size, snd_strerror(err)); goto fail; } *fragsize = period_size; periods = *fragnr; dir = 0; if ((err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &periods, &dir)) < 0) { log_message(LOG_DEFAULT, "Unable to set periods %i for playback: %s", periods, snd_strerror(err)); goto fail; } *fragnr = periods; alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams); if ((err = snd_pcm_hw_params(handle, hwparams)) < 0) { log_message(LOG_DEFAULT, "Unable to set hw params for playback: %s", snd_strerror(err)); goto fail; } alsa_bufsize = (*fragsize)*(*fragnr); alsa_fragsize = *fragsize; alsa_channels = *channels; return 0; fail: snd_pcm_close(handle); handle = NULL; return 1; }
static void NTO_PlayAudio(_THIS) { int written, rval; int towrite; void* pcmbuffer; if (!this->enabled) { return; } towrite = this->spec.size; pcmbuffer = pcm_buf; /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ do { written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); if (written != towrite) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* Let a little CPU time go by and try to write again */ SDL_Delay(1); /* if we wrote some data */ towrite -= written; pcmbuffer += written * this->spec.channels; continue; } else { if ((errno == EINVAL) || (errno == EIO)) { SDL_memset(&cstatus, 0, sizeof(cstatus)); cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; if ((rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) { SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", snd_strerror(rval)); return; } if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY)) { if ((rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) { SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval)); return; } } continue; } else { return; } } } else { /* we wrote all remaining data */ towrite -= written; pcmbuffer += written * this->spec.channels; } } while ((towrite > 0) && (this->enabled)); /* If we couldn't write, assume fatal error for now */ if (towrite != 0) { this->enabled = 0; } return; }
int main(int argc, char ** argv) { // Variable declaration int rc; char * buffer; int buffer_size; int periods_per_buffer; snd_pcm_t *handle; snd_pcm_hw_params_t *params; snd_pcm_uframes_t frames; unsigned int channels; unsigned int rate; wav_header * wav_header_info; FILE * fp; // Argument parsing if (argc != 2) { printf("Incorrect usage: Enter filename of the wav file you want to play as an argument: %s filename.txt\n", argv[0]); return 1; } // Open wav file to read fp = fopen(argv[1], "rb"); if (fp == NULL) { printf("ERROR: %s does not exist, or cannot be opened.\n", argv[1]); return 1; } wav_header_info = malloc(44); fread(wav_header_info, 1, 44, fp); // print_wav_header(wav_header_info); // Assign variables that were read from the wave file channels = wav_header_info->number_of_channels; rate = wav_header_info->sample_rate; periods_per_buffer = 2; // Down to user preference, depending on size of internal ring buffer of ALSA // Open PCM device for playback if ((rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("ERROR: Cannot open pcm device. %s\n", snd_strerror(rc)); } // Allocate hardware parameters if ((rc = snd_pcm_hw_params_malloc(¶ms)) < 0) { printf("ERROR: Cannot allocate hardware parameters. %s\n", snd_strerror(rc)); } // Initialize parameters with default values if ((rc = snd_pcm_hw_params_any(handle, params)) < 0) { printf("ERROR: Cannot initialize hardware parameters. %s\n", snd_strerror(rc)); } // Setting hardware parameters if ((rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { printf("ERROR: Cannot set interleaved mode. %s\n", snd_strerror(rc)); } if ((rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0) { printf("ERROR: Cannot set PCM format. %s\n", snd_strerror(rc)); } if ((rc = snd_pcm_hw_params_set_channels_near(handle, params, &channels)) < 0) { printf("ERROR: Cannot set number of channels. %s\n", snd_strerror(rc)); } if ((rc = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0)) < 0) { printf("ERROR: Cannot set plyabck rate. %s\n", snd_strerror(rc)); } if ((rc = snd_pcm_hw_params(handle, params)) < 0) { printf("ERROR: Cannot set hardware parameters. %s\n", snd_strerror(rc)); } // Get hardware parameters if ((rc = snd_pcm_hw_params_get_period_size(params, &frames, 0)) < 0) { printf("Playback ERROR: Can't get period size. %s\n", snd_strerror(rc)); } printf("Frames: %lu\n", frames); if ((rc = snd_pcm_hw_params_get_channels(params, &channels)) < 0) { printf("Playback ERROR: Can't get channel number. %s\n", snd_strerror(rc)); } if ((rc = snd_pcm_hw_params_get_rate(params, &rate, 0)) < 0) { printf("ERROR: Cannot get rate. %s\n", snd_strerror(rc)); } // Free paraemeters snd_pcm_hw_params_free(params); // Create buffer buffer_size = frames * periods_per_buffer * channels * sizeof(int16_t); /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(buffer_size); // Send info to ALSA //while ((rc = read(0, buffer, buffer_size)) != 0) while (rc = fread(buffer, 1, periods_per_buffer * frames * channels * sizeof(int16_t), fp) != 0) { rc = snd_pcm_writei(handle, buffer, frames * periods_per_buffer); if (rc == -EPIPE) { fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { printf("ERROR: Cannot write to playback device. %s\n", strerror(rc)); } } printf("Info set: Device is now draining...\n"); snd_pcm_drain(handle); printf("Done playing, closing connections.\n"); snd_pcm_close(handle); free(wav_header_info); free(buffer); fclose(fp); return 0; }
static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec) { int rval; int format; Uint16 test_format; int found; audio_handle = NULL; this->enabled = 0; if (pcm_buf != NULL) { SDL_FreeAudioMem(pcm_buf); pcm_buf = NULL; } /* initialize channel transfer parameters to default */ NTO_InitAudioParams(&cparams); /* Open the audio device */ rval = snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS); if (rval < 0) { SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", snd_strerror(rval)); return (-1); } if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) { /* enable count status parameter */ if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP)) < 0) { SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval)); return (-1); } } /* Try for a closest match on audio format */ format = 0; /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ found = 0; for (test_format=SDL_FirstAudioFormat(spec->format); !found ;) { /* if match found set format to equivalent ALSA format */ switch (test_format) { case AUDIO_U8: format = SND_PCM_SFMT_U8; found = 1; break; case AUDIO_S8: format = SND_PCM_SFMT_S8; found = 1; break; case AUDIO_S16LSB: format = SND_PCM_SFMT_S16_LE; found = 1; break; case AUDIO_S16MSB: format = SND_PCM_SFMT_S16_BE; found = 1; break; case AUDIO_U16LSB: format = SND_PCM_SFMT_U16_LE; found = 1; break; case AUDIO_U16MSB: format = SND_PCM_SFMT_U16_BE; found = 1; break; default: break; } if (!found) { test_format = SDL_NextAudioFormat(); } } /* assumes test_format not 0 on success */ if (test_format == 0) { SDL_SetError("NTO_OpenAudio(): Couldn't find any hardware audio formats"); return (-1); } spec->format = test_format; /* Set the audio format */ cparams.format.format = format; /* Set mono or stereo audio (currently only two channels supported) */ cparams.format.voices = spec->channels; /* Set rate */ cparams.format.rate = spec->freq; /* Setup the transfer parameters according to cparams */ rval = snd_pcm_plugin_params(audio_handle, &cparams); if (rval < 0) { SDL_SetError("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", snd_strerror(rval)); return (-1); } /* Make sure channel is setup right one last time */ SDL_memset(&csetup, 0x00, sizeof(csetup)); csetup.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) { SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n"); return -1; } /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(spec); pcm_len = spec->size; if (pcm_len==0) { pcm_len = csetup.buf.block.frag_size * spec->channels * (snd_pcm_format_width(format)/8); } /* Allocate memory to the audio buffer and initialize with silence (Note that buffer size must be a multiple of fragment size, so find closest multiple) */ pcm_buf = (Uint8*)SDL_AllocAudioMem(pcm_len); if (pcm_buf == NULL) { SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n"); return (-1); } SDL_memset(pcm_buf, spec->silence, pcm_len); /* get the file descriptor */ if ((audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) { SDL_SetError("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", snd_strerror(rval)); return (-1); } /* Trigger audio playback */ rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK); if (rval < 0) { SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval)); return (-1); } this->enabled = 1; /* Get the parent process id (we're the parent of the audio thread) */ parent = getpid(); /* We're really ready to rock and roll. :-) */ return (0); }
int main( int argc, char ** argv ) { const char *device = "default"; /* playback device */ unsigned char buffer[ 16*1024 ]; /* read buffer */ int err; snd_pcm_t *handle; snd_pcm_sframes_t frames; FILE * fp = 0; size_t bytes_read; int blocking_flag = 0; // 0 = blocking; SND_PCM_NONBLOCK = not blocking // check file argument if ( argc <= 1 ) { printf( "no input\n" ); return 127; } // open the file for reading fp = fopen( argv[1], "rb" ); if ( !fp ) { printf("error: couldn't open: %s\n", argv[1]); exit(EXIT_FAILURE); } // discard the header fread( buffer, 1, 44, fp ); // open the PCM device if ( (err = snd_pcm_open( &handle, device, SND_PCM_STREAM_PLAYBACK, blocking_flag )) < 0 ) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // setup our pcm state (on the snd_pcm_t handle) if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 16000, 1, 50000)) < 0) { /* 0.05 sec */ printf("Playback open error: %s\n", snd_strerror(err)); exit( EXIT_FAILURE ); } // read loop while( 1 ) { bytes_read = fread( buffer, 1, sizeof(buffer), fp ); if ( bytes_read == 0 ) { break; } frames = snd_pcm_writei( handle, buffer, bytes_read / 2 /*(frame is 16-bit)*/ ); if (frames < 0) { printf( "error: snd_pcm_writei: %s\n", snd_strerror( frames ) ); fflush( stdout ); frames = snd_pcm_recover(handle, frames, 0); } if (frames < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(frames)); fflush( stdout ); break; } if ( frames > 0 ) { printf("Played %li frames\n", frames); } } fclose( fp ); snd_pcm_close( handle ); return 0; }
int main() { long loops; int rc,j = 0; int size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; unsigned int val,val2; int dir; snd_pcm_uframes_t frames; char *buffer; FILE *fp ; if( (fp = fopen("sound.wav","r")) < 0)//南拳妈妈 - 你不像她.wav printf("open sound.wav fial\n"); if(fseek(fp,0,SEEK_SET) < 0) printf("put fp start to first error\n "); /* Open PCM device for playback. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s/n", snd_strerror(rc)); exit(1); } /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ snd_pcm_hw_params_any(handle, params); /* Set the desired hardware parameters. */ /* Interleaved mode */ snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, 1); /* 44100 bits/second sampling rate (CD quality) */ val = 8000; snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); /* Set period size to 32 frames. */ frames = 1024; //设置的值没有反应 snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); // printf("frames is %d\n",(int)frames); /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s/n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ snd_pcm_hw_params_get_period_size(params, &frames, &dir); size = frames * 2; /* 2 bytes/sample, 2 channels */ buffer = (char *) malloc(size); /* We want to loop for 5 seconds */ snd_pcm_hw_params_get_period_time(params, &val, &dir); /* 5 seconds in microseconds divided by * period time */ loops = 10000000 / val; while (loops > 0) { loops--; rc = fread(buffer,1, size,fp); //rc = read(0,buffer,size); //printf("%d\n",j++); if (rc == 0) { fprintf(stderr, "end of file on input\n"); break; } else if (rc != size) { fprintf(stderr, "short read: read %d bytes\n", rc); } //else printf("fread to buffer success\n"); rc = snd_pcm_writei(handle, buffer, frames); if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from writei: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short write, write %d frames\n", rc); } } /*******************************************************************/ snd_pcm_drain(handle); snd_pcm_close(handle); free(buffer); fclose(fp); return 0; }
static void alsa_error(const char *msg, int r) { fprintf(stderr, "ALSA %s: %s\n", msg, snd_strerror(r)); }
int run(char *filename) { capture_stop = 0; char *pcm_name = "default"; int tmp, err; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); err = snd_output_stdio_attach(&log, stderr, 0); assert(err >= 0); file_type = FORMAT_DEFAULT; stream = SND_PCM_STREAM_CAPTURE; file_type = FORMAT_WAVE; command = "arecord"; start_delay = 1; chunk_size = -1; rhwparams.format = DEFAULT_FORMAT; rhwparams.rate = DEFAULT_SPEED; rhwparams.channels = 1; file_type = FORMAT_WAVE; // cdr: // rhwparams.format = SND_PCM_FORMAT_S16_BE; rhwparams.format = file_type == FORMAT_AU ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE; rhwparams.rate = 44100; rhwparams.channels = 2; err = snd_pcm_open(&handle, pcm_name, stream, open_mode); if (err < 0) { error(_("audio open error: %s"), snd_strerror(err)); return 1; } if ((err = snd_pcm_info(handle, info)) < 0) { error(_("info error: %s"), snd_strerror(err)); return 1; } if (nonblock) { err = snd_pcm_nonblock(handle, 1); if (err < 0) { error(_("nonblock setting error: %s"), snd_strerror(err)); return 1; } } chunk_size = 1024; hwparams = rhwparams; audiobuf = (u_char *)malloc(1024); if (audiobuf == NULL) { error(_("not enough memory")); return 1; } writei_func = snd_pcm_writei; readi_func = snd_pcm_readi; writen_func = snd_pcm_writen; readn_func = snd_pcm_readn; //signal(SIGINT, signal_handler); //signal(SIGTERM, signal_handler); //signal(SIGABRT, signal_handler); capture(filename); if (fmt_rec_table[file_type].end) { fmt_rec_table[file_type].end(fd); fd = -1; } stream = -1; if (fd > 1) { close(fd); fd = -1; } if (handle) { snd_pcm_close(handle); handle = NULL; } //snd_pcm_close(handle); //free(audiobuf); //snd_output_close(log); //snd_config_update_free_global(); return EXIT_SUCCESS; }
// returns TRUE if successful int setHWParams(AlsaPcmInfo* info, float sampleRate, int channels, int bufferSizeInFrames, snd_pcm_format_t format) { unsigned int rrate; int ret, dir, periods, periodTime; snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; /* choose all parameters */ ret = snd_pcm_hw_params_any(info->handle, info->hwParams); if (ret < 0) { ERROR1("Broken configuration: no configurations available: %s\n", snd_strerror(ret)); return FALSE; } /* set the interleaved read/write format */ ret = snd_pcm_hw_params_set_access(info->handle, info->hwParams, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { ERROR1("SND_PCM_ACCESS_RW_INTERLEAVED access type not available: %s\n", snd_strerror(ret)); return FALSE; } /* set the sample format */ ret = snd_pcm_hw_params_set_format(info->handle, info->hwParams, format); if (ret < 0) { ERROR1("Sample format not available: %s\n", snd_strerror(ret)); return FALSE; } /* set the count of channels */ ret = snd_pcm_hw_params_set_channels(info->handle, info->hwParams, channels); if (ret < 0) { ERROR2("Channels count (%d) not available: %s\n", channels, snd_strerror(ret)); return FALSE; } /* set the stream rate */ rrate = (int) (sampleRate + 0.5f); #ifdef ALSA_PCM_NEW_HW_PARAMS_API dir = 0; ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); #else ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, rrate, 0); #endif if (ret < 0) { ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); return FALSE; } if ((rrate-sampleRate > 2) || (rrate-sampleRate < - 2)) { ERROR2("Rate doesn't match (requested %2.2fHz, got %dHz)\n", sampleRate, rrate); return FALSE; } /* set the buffer time */ #ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); #else ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, alsaBufferSizeInFrames); #endif if (ret < 0) { ERROR2("Unable to set buffer size to %d frames: %s\n", (int) alsaBufferSizeInFrames, snd_strerror(ret)); return FALSE; } bufferSizeInFrames = (int) alsaBufferSizeInFrames; /* set the period time */ if (bufferSizeInFrames > 1024) { dir = 0; periodTime = DEFAULT_PERIOD_TIME; #ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); #else periodTime = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, periodTime, &dir); ret = periodTime; #endif if (ret < 0) { ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); return FALSE; } } else { /* set the period count for very small buffer sizes to 2 */ dir = 0; periods = 2; #ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); #else periods = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, periods, &dir); ret = periods; #endif if (ret < 0) { ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); return FALSE; } } /* write the parameters to device */ ret = snd_pcm_hw_params(info->handle, info->hwParams); if (ret < 0) { ERROR1("Unable to set hw params: %s\n", snd_strerror(ret)); return FALSE; } return TRUE; }
bool AlsaSound::AlsaInit() { unsigned int sample_rate = m_mixer->GetSampleRate(); int err; int dir; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_t *hwparams; snd_pcm_uframes_t buffer_size,buffer_size_max; unsigned int periods; err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err)); return false; } snd_pcm_hw_params_alloca(&hwparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); if (err < 0) { ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err)); return false; } dir = 0; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &sample_rate, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_channels(handle, hwparams, CHANNEL_COUNT); if (err < 0) { ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err)); return false; } periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN; err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Cannot set maximum periods per buffer: %s\n", snd_strerror(err)); return false; } buffer_size_max = BUFFER_SIZE_MAX; err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams, &buffer_size_max); if (err < 0) { ERROR_LOG(AUDIO, "Cannot set maximum buffer size: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (err < 0) { ERROR_LOG(AUDIO, "Cannot get buffer size: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_get_periods_max(hwparams, &periods, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Cannot get periods: %s\n", snd_strerror(err)); return false; } //periods is the number of fragments alsa can wait for during one //buffer_size frames_to_deliver = buffer_size / periods; //limit the minimum size. pulseaudio advertises a minimum of 32 samples. if (frames_to_deliver < FRAME_COUNT_MIN) frames_to_deliver = FRAME_COUNT_MIN; //it is probably a bad idea to try to send more than one buffer of data if ((unsigned int)frames_to_deliver > buffer_size) frames_to_deliver = buffer_size; NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d samples per fragments.\n", buffer_size, periods, frames_to_deliver); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); if (err < 0) { ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err)); return false; } err = snd_pcm_sw_params(handle, swparams); if (err < 0) { ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_prepare(handle); if (err < 0) { ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err)); return false; } NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n"); return true; }
int main(int argc, char *argv[]) { int err; struct sniffer_state sts; sts.pcm_name = strdup("plughw:0,0"); sts.stream = SND_PCM_STREAM_PLAYBACK; sts.format = SND_PCM_FORMAT_A_LAW; sts.rate = 8000; // sts.exact_rate; sts.periods = 2; sts.buffer_time = 25000; sts.period_time = 12500; snd_pcm_hw_params_alloca(&sts.hwparams); if (snd_pcm_open(&sts.pcm, sts.pcm_name, sts.stream, 0) < 0) { fprintf(stderr, "Error opening PCM device %s\n", sts.pcm_name); return(-1); } if (snd_pcm_hw_params_any(sts.pcm, sts.hwparams) < 0) { fprintf(stderr, "Can not configure this PCM device.\n"); return(-1); } if (snd_pcm_hw_params_set_access(sts.pcm, sts.hwparams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) < 0) { fprintf(stderr, "Error setting access.\n"); return(-1); } if (snd_pcm_hw_params_set_format(sts.pcm, sts.hwparams, sts.format) < 0) { fprintf(stderr, "Error setting format.\n"); return(-1); } sts.exact_rate = sts.rate; if (snd_pcm_hw_params_set_rate_near(sts.pcm, sts.hwparams, &sts.exact_rate, 0) < 0) { fprintf(stderr, "Error setting rate.\n"); return(-1); } printf("rate: %d\n", sts.exact_rate); if (sts.rate != sts.exact_rate) { fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n" "==> Using %d Hz instead.\n", sts.rate, sts.exact_rate); } if (snd_pcm_hw_params_set_channels(sts.pcm, sts.hwparams, 1) < 0) { fprintf(stderr, "Error setting channels.\n"); return(-1); } if (snd_pcm_hw_params_set_periods(sts.pcm, sts.hwparams, sts.periods, 0) < 0) { fprintf(stderr, "Error setting periods.\n"); return(-1); } if (snd_pcm_hw_params_set_buffer_time_near(sts.pcm, sts.hwparams, &sts.buffer_time, &sts.dir) < 0) { fprintf(stderr, "Error setting buffersize.\n"); return(-1); } printf("buffer_time set to %d\n", sts.buffer_time); err = snd_pcm_hw_params_get_period_size(sts.hwparams, &sts.period_size, &sts.dir); if (err < 0) { printf("Unable to get period size for playback: %s\n", snd_strerror(err)); return err; } printf("period_size = %d\n", (int)sts.period_size); if (snd_pcm_hw_params(sts.pcm, sts.hwparams) < 0) { fprintf(stderr, "Error setting HW params.\n"); return(-1); } setvbuf(stdout, (char *)NULL, _IONBF, 0); int router_control_fd = open("/dev/visdn/router-control", O_RDWR); if (router_control_fd < 0) { perror("Unable to open router-control"); return 1; } int fd; fd = open("/dev/visdn/streamport", O_RDWR); if (fd < 0) { perror("cannot open /dev/visdn/streamport"); return 1; } struct vsp_ctl vsp_ctl; if (ioctl(fd, VISDN_SP_GET_NODEID, (caddr_t)&vsp_ctl) < 0) { perror("ioctl(VISDN_SP_GET_NODEID)"); return 1; } char node_id[80]; snprintf(node_id, sizeof(node_id), "/sys/%s", vsp_ctl.node_id); struct visdn_connect vc; memset(&vc, 0, sizeof(vc)); strncpy(vc.from_endpoint, argv[1], sizeof(vc.from_endpoint)); strncpy(vc.to_endpoint, node_id, sizeof(vc.to_endpoint)); printf("Connect: %s => %s\n", vc.from_endpoint, vc.to_endpoint); if (ioctl(router_control_fd, VISDN_IOC_CONNECT, (caddr_t) &vc) < 0) { perror("ioctl(VISDN_CONNECT, br=>sp)"); return 1; } int pipeline_id = vc.pipeline_id; memset(&vc, 0, sizeof(vc)); vc.pipeline_id = pipeline_id; if (ioctl(router_control_fd, VISDN_IOC_PIPELINE_OPEN, (caddr_t)&vc) < 0) { perror("ioctl(VISDN_PIPELINE_OPEN, br=>sp)"); return 1; } memset(&vc, 0, sizeof(vc)); vc.pipeline_id = pipeline_id; if (ioctl(router_control_fd, VISDN_IOC_PIPELINE_START, (caddr_t)&vc) < 0) { perror("ioctl(VISDN_PIPELINE_START, br=>sp)"); return 1; } //double phase = 0; const snd_pcm_channel_area_t *my_areas; snd_pcm_uframes_t offset, frames, size; snd_pcm_sframes_t avail, commitres; snd_pcm_state_t state; int first = 1; while (1) { state = snd_pcm_state(sts.pcm); if (state == SND_PCM_STATE_XRUN) { err = xrun_recovery(sts.pcm, -EPIPE); if (err < 0) { printf("XRUN recovery failed: %s\n", snd_strerror(err)); return err; } first = 1; } else if (state == SND_PCM_STATE_SUSPENDED) { err = xrun_recovery(sts.pcm, -ESTRPIPE); if (err < 0) { printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); return err; } } avail = snd_pcm_avail_update(sts.pcm); if (avail < 0) { err = xrun_recovery(sts.pcm, avail); if (err < 0) { printf("avail update failed: %s\n", snd_strerror(err)); return err; } first = 1; continue; } if (avail < sts.period_size) { if (first) { first = 0; err = snd_pcm_start(sts.pcm); if (err < 0) { printf("Start error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } } else { err = snd_pcm_wait(sts.pcm, -1); if (err < 0) { if ((err = xrun_recovery(sts.pcm, err)) < 0) { printf("snd_pcm_wait error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } } continue; } size = sts.period_size; while (size > 0) { frames = size; err = snd_pcm_mmap_begin(sts.pcm, &my_areas, &offset, &frames); if (err < 0) { if ((err = xrun_recovery(sts.pcm, err)) < 0) { printf("MMAP begin avail error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } int r = read(fd, my_areas[0].addr + offset, frames); printf("%d %d %d: ", (int)offset, (int)frames, r); int i; for (i=0; i<r; i++) printf("%02x", *(__u8 *)(my_areas[0].addr + i)); printf("\n"); commitres = snd_pcm_mmap_commit(sts.pcm, offset, frames); if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { if ((err = xrun_recovery(sts.pcm, commitres >= 0 ? -EPIPE : commitres)) < 0) { printf("MMAP commit error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } size -= frames; } } return 0; }
/************************************************************************** * wodPlayer_Reset [internal] * * wodPlayer helper. Resets current output stream. */ static void wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset) { int err; TRACE("(%p)\n", wwo); wodUpdatePlayedTotal(wwo, NULL); /* updates current notify list */ wodPlayer_NotifyCompletions(wwo, FALSE); if ( (err = snd_pcm_drop(wwo->pcm)) < 0) { FIXME("flush: %s\n", snd_strerror(err)); wwo->hThread = 0; wwo->state = WINE_WS_STOPPED; ExitThread(-1); } if ( (err = snd_pcm_prepare(wwo->pcm)) < 0 ) ERR("pcm prepare failed: %s\n", snd_strerror(err)); if (reset) { enum win_wm_message msg; DWORD_PTR param; HANDLE ev; /* remove any buffer */ wodPlayer_NotifyCompletions(wwo, TRUE); wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL; wwo->state = WINE_WS_STOPPED; wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0; /* Clear partial wavehdr */ wwo->dwPartialOffset = 0; /* remove any existing message in the ring */ EnterCriticalSection(&wwo->msgRing.msg_crst); /* return all pending headers in queue */ while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, ¶m, &ev)) { if (msg != WINE_WM_HEADER) { FIXME("shouldn't have headers left\n"); SetEvent(ev); continue; } ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE; ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE; wodNotifyClient(wwo, WOM_DONE, param, 0); } ALSA_ResetRingMessage(&wwo->msgRing); LeaveCriticalSection(&wwo->msgRing.msg_crst); } else { if (wwo->lpLoopPtr) { /* complicated case, not handled yet (could imply modifying the loop counter */ FIXME("Pausing while in loop isn't correctly handled yet, expect strange results\n"); wwo->lpPlayPtr = wwo->lpLoopPtr; wwo->dwPartialOffset = 0; wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */ } else { LPWAVEHDR ptr; DWORD sz = wwo->dwPartialOffset; /* reset all the data as if we had written only up to lpPlayedTotal bytes */ /* compute the max size playable from lpQueuePtr */ for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext) { sz += ptr->dwBufferLength; } /* because the reset lpPlayPtr will be lpQueuePtr */ if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("grin\n"); wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal); wwo->dwWrittenTotal = wwo->dwPlayedTotal; wwo->lpPlayPtr = wwo->lpQueuePtr; } wwo->state = WINE_WS_PAUSED; } }