/** * \brief Wait for a PCM to become ready * \param pcm ordinary PCM handle * \param timeout maximum time in milliseconds to wait * \return a positive value on success otherwise a negative error code * \retval 0 timeout occurred * \retval 1 PCM stream is ready for I/O */ int sndo_pcm_wait(sndo_pcm_t *pcm, int timeout) { struct pollfd pfd[2]; unsigned short p_revents, c_revents; int err; err = snd_pcm_poll_descriptors(pcm->playback, &pfd[0], 1); assert(err == 1); err = snd_pcm_poll_descriptors(pcm->capture, &pfd[1], 1); assert(err == 1); err = poll(pfd, 2, timeout); if (err < 0) return -errno; if (err == 0) return 0; do { err = snd_pcm_poll_descriptors_revents(pcm->playback, &pfd[0], 1, &p_revents); if (err < 0) return err; if (p_revents & (POLLERR | POLLNVAL)) return -EIO; err = snd_pcm_poll_descriptors_revents(pcm->capture, &pfd[1], 1, &c_revents); if (err < 0) return err; if (c_revents & (POLLERR | POLLNVAL)) return -EIO; if ((p_revents & POLLOUT) && (c_revents & POLLIN)) return 1; err = poll(&pfd[(p_revents & POLLOUT) ? 1 : 0], 1, 1); if (err < 0) return err; } while (1); }
void alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { int err; struct pollfd *f; if (out_handle && !rdpsnd_queue_empty()) { num_fds_out = snd_pcm_poll_descriptors_count(out_handle); if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out)) return; err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out); if (err < 0) return; for (f = pfds_out; f < &pfds_out[num_fds_out]; f++) { if (f->events & POLLIN) FD_SET(f->fd, rfds); if (f->events & POLLOUT) FD_SET(f->fd, wfds); if (f->fd > *n && (f->events & (POLLIN | POLLOUT))) *n = f->fd; } } if (in_handle) { num_fds_in = snd_pcm_poll_descriptors_count(in_handle); if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in)) return; err = snd_pcm_poll_descriptors(in_handle, pfds_in, num_fds_in); if (err < 0) return; for (f = pfds_in; f < &pfds_in[num_fds_in]; f++) { if (f->events & POLLIN) FD_SET(f->fd, rfds); if (f->events & POLLOUT) FD_SET(f->fd, wfds); if (f->fd > *n && (f->events & (POLLIN | POLLOUT))) *n = f->fd; } } }
static char poll_setup (void) { if (pipe (poll_pipe)) { ERROR ("Failed to create pipe: %s.\n", strerror (errno)); return 0; } if (fcntl (poll_pipe[0], F_SETFL, O_NONBLOCK)) { ERROR ("Failed to set O_NONBLOCK on pipe: %s.\n", strerror (errno)); close (poll_pipe[0]); close (poll_pipe[1]); return 0; } poll_count = 1 + snd_pcm_poll_descriptors_count (alsa_handle); poll_handles = g_new (struct pollfd, poll_count); poll_handles[0].fd = poll_pipe[0]; poll_handles[0].events = POLLIN; poll_count = 1 + snd_pcm_poll_descriptors (alsa_handle, poll_handles + 1, poll_count - 1); return 1; }
int audioStreamer_ALSA::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data { int ret; if (m_sleep >= 0) { struct pollfd pfds[32]; int cnt=snd_pcm_poll_descriptors(pcm_handle,pfds,32); if (cnt>0) poll(pfds,cnt,m_sleep); } ret=snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8))); if (ret < 0) { if (ret != -EAGAIN) { snd_pcm_prepare(pcm_handle); } return 0; } #if 0 snd_pcm_sframes_t del=0; if (!snd_pcm_delay(pcm_handle,&del) && del > m_bufsize/2 /* JF>used to be /1 */) { audiostream_onover(); for (;;) if (snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8)))<0) break; // we have too many samples, eat some } #endif return ret*m_nch*(m_bps/8); }
/* Oversimplistic fileno() implementation assuming there's only one file- * descriptor involved. Should be the case anyway */ int audio_fileno(void) { struct pollfd pfd; snd_pcm_poll_descriptors(playback_handle, &pfd, 1); return pfd.fd; }
AudioAlsa::AudioAlsa( bool & _success_ful, Mixer* _mixer ) : AudioDevice( tLimit<ch_cnt_t>( ConfigManager::inst()->value( "audioalsa", "channels" ).toInt(), DEFAULT_CHANNELS, SURROUND_CHANNELS ), _mixer ), m_handle( NULL ), m_hwParams( NULL ), m_swParams( NULL ), m_convertEndian( false ) { _success_ful = false; int err; if( ( err = snd_pcm_open( &m_handle, probeDevice().toLatin1().constData(), SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 ) { printf( "Playback open error: %s\n", snd_strerror( err ) ); return; } snd_pcm_hw_params_malloc( &m_hwParams ); snd_pcm_sw_params_malloc( &m_swParams ); if( ( err = setHWParams( channels(), SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 ) { printf( "Setting of hwparams failed: %s\n", snd_strerror( err ) ); return; } if( ( err = setSWParams() ) < 0 ) { printf( "Setting of swparams failed: %s\n", snd_strerror( err ) ); return; } // set FD_CLOEXEC flag for all file descriptors so forked processes // do not inherit them struct pollfd * ufds; int count = snd_pcm_poll_descriptors_count( m_handle ); ufds = new pollfd[count]; snd_pcm_poll_descriptors( m_handle, ufds, count ); for( int i = 0; i < qMax( 3, count ); ++i ) { const int fd = ( i >= count ) ? ufds[0].fd+i : ufds[i].fd; int oldflags = fcntl( fd, F_GETFD, 0 ); if( oldflags < 0 ) continue; oldflags |= FD_CLOEXEC; fcntl( fd, F_SETFD, oldflags ); } delete[] ufds; _success_ful = true; }
static void alsa_write( char *buf, int size ) { struct pollfd pfd; snd_pcm_poll_descriptors( alsa.pcm, &pfd, 1 ); poll( &pfd, 1, -1 ); snd_pcm_writei( alsa.pcm, buf, size/alsa.bpf ); }
/** * \brief get poll descriptors * \param pcm ordinary pcm handle * \param pfds array of poll descriptors * \param space space in the poll descriptor array * \return count of filled descriptors */ int sndo_pcm_poll_descriptors(sndo_pcm_t *pcm, struct pollfd *pfds, unsigned int space) { int playback, err, res = 0; playback = snd_pcm_poll_descriptors_count(pcm->playback); if (playback < 0) return playback; err = snd_pcm_poll_descriptors(pcm->playback, pfds, (unsigned)playback < space ? (unsigned)playback : space); if (err < 0) return err; res += err; if ((unsigned)res < space) { err = snd_pcm_poll_descriptors(pcm->capture, pfds + res, space - res); if (err < 0) return err; res += err; } return res; }
/* FIXME: proper lock? */ static void* alsa_loop(void* arg) { int npfds = snd_pcm_poll_descriptors_count(alsa_pcm); struct pollfd* pfds; unsigned short* revents; if(npfds <= 0) goto _error; //printf("Starting alsa_loop thread...\n"); pfds = alloca(sizeof(*pfds) * npfds); revents = alloca(sizeof(*revents) * npfds); while(going && alsa_pcm) { if(get_thread_buffer_filled() > prebuffer_size) prebuffer = false; if(!prebuffer && get_thread_buffer_filled() > hw_period_size_in) { snd_pcm_poll_descriptors(alsa_pcm, pfds, npfds); if(poll(pfds, npfds, 10) > 0) { /* * need to check revents. poll() with * dmix returns a postive value even * if no data is available */ int i; snd_pcm_poll_descriptors_revents(alsa_pcm, pfds, npfds, revents); for(i = 0; i < npfds; i++) if(revents[i] & POLLOUT) { alsa_write_out_thread_data(); break; } } } else usleep(10000); if(flush_request != -1) { alsa_do_flush(flush_request); flush_request = -1; prebuffer = true; } } _error: alsa_close_pcm(); free(thread_buffer); thread_buffer = NULL; pthread_exit(NULL); }
int main (int argc, char *argv[]) { int nfds, seq_nfds, l1; struct pollfd *pfds; if (argc < 6) { fprintf(stderr, "LinzerSchnitteMIDI <hw:0,0,1> <attack> <decay> <sustain> <release>\n"); exit(1); } attack = atof(argv[2]); decay = atof(argv[3]); sustain = atof(argv[4]); release = atof(argv[5]); /* polyphony = atoi(argv[6]); buffersize = atoi(argv[7]); outputvolume = atoi(argv[8]); firstnotefreq = atoi(argv[9]); freqchannelwidth = atoi(argv[10]); */ buf = (short *) malloc (2 * sizeof (short) * BUFSIZE); playback_handle = open_pcm(argv[1]); seq_handle = open_seq(); seq_nfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); nfds = snd_pcm_poll_descriptors_count (playback_handle); pfds = (struct pollfd *)alloca(sizeof(struct pollfd) * (seq_nfds + nfds)); snd_seq_poll_descriptors(seq_handle, pfds, seq_nfds, POLLIN); snd_pcm_poll_descriptors (playback_handle, pfds+seq_nfds, nfds); connect2MidiThroughPort(seq_handle); for (l1 = 0; l1 < POLY; note_active[l1++] = 0); while (1) { if (poll (pfds, seq_nfds + nfds, 1000) > 0) { for (l1 = 0; l1 < seq_nfds; l1++) { if (pfds[l1].revents > 0) midi_callback(); } for (l1 = seq_nfds; l1 < seq_nfds + nfds; l1++) { if (pfds[l1].revents > 0) { if (playback_callback(BUFSIZE) < BUFSIZE) { fprintf (stderr, "xrun ! increase buffer \n"); snd_pcm_prepare(playback_handle); } } } } } snd_pcm_close (playback_handle); snd_seq_close (seq_handle); free(buf); return (0); }
static void Poll (snd_pcm_t *pcm, int canc) { int n = snd_pcm_poll_descriptors_count (pcm); struct pollfd ufd[n]; unsigned short revents; snd_pcm_poll_descriptors (pcm, ufd, n); do { vlc_restorecancel (canc); while (poll (ufd, n, -1) == -1); canc = vlc_savecancel (); snd_pcm_poll_descriptors_revents (pcm, ufd, n, &revents); } while (!revents); }
int main (int argc, char *argv[]) { int nfds, seq_nfds, l1; struct pollfd *pfds; if (argc < 10) { fprintf(stderr, "miniFMsynth <device> <FM> <harmonic> <subharmonic> <transpose> <a> <d> <s> <r>\n"); exit(1); } modulation = atof(argv[2]); harmonic = atoi(argv[3]); subharmonic = atoi(argv[4]); transpose = atoi(argv[5]); attack = atof(argv[6]); decay = atof(argv[7]); sustain = atof(argv[8]); release = atof(argv[9]); pitch = 0; buf = (short *) malloc (2 * sizeof (short) * BUFSIZE); playback_handle = open_pcm(argv[1]); seq_handle = open_seq(); seq_nfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); nfds = snd_pcm_poll_descriptors_count (playback_handle); pfds = (struct pollfd *)alloca(sizeof(struct pollfd) * (seq_nfds + nfds)); snd_seq_poll_descriptors(seq_handle, pfds, seq_nfds, POLLIN); snd_pcm_poll_descriptors (playback_handle, pfds+seq_nfds, nfds); for (l1 = 0; l1 < POLY; note_active[l1++] = 0); while (1) { if (poll (pfds, seq_nfds + nfds, 1000) > 0) { for (l1 = 0; l1 < seq_nfds; l1++) { if (pfds[l1].revents > 0) midi_callback(); } for (l1 = seq_nfds; l1 < seq_nfds + nfds; l1++) { if (pfds[l1].revents > 0) { if (playback_callback(BUFSIZE) < BUFSIZE) { fprintf (stderr, "xrun !\n"); snd_pcm_prepare(playback_handle); } } } } } snd_pcm_close (playback_handle); snd_seq_close (seq_handle); free(buf); return (0); }
void alsa_poll_descriptors(alsa_dev_t *alsa_dev, struct pollfd **pfds, int *count) { int32_t rc; *count = snd_pcm_poll_descriptors_count(alsa_dev->snd_pcm); if (*count <= 0) { syslog(LOG_ERR, "Invalid poll descriptors count"); exit(EXIT_FAILURE); } *pfds = malloc(sizeof(struct pollfd) * (*count)); memset(*pfds, 0, sizeof(struct pollfd) * (*count)); rc = snd_pcm_poll_descriptors(alsa_dev->snd_pcm, *pfds, *count); if (rc < 0) { syslog(LOG_ERR, "Unable to obtain poll descriptors for capture: %s", snd_strerror(rc)); exit(EXIT_FAILURE); } }
static ssize_t pcm_pollfds(struct alsa_pcm *alsa, struct pollfd *pe, size_t z) { int r, count; count = snd_pcm_poll_descriptors_count(alsa->pcm); if (count > z) return -1; if (count == 0) alsa->pe = NULL; else { r = snd_pcm_poll_descriptors(alsa->pcm, pe, count); if (r < 0) { alsa_error("poll_descriptors", r); return -1; } alsa->pe = pe; } alsa->pe_count = count; return count; }
void* startSnd(void *arg){ sndbuf = (short *) malloc (2 * sizeof (short) * BUFSAMPS); //each sample is 2 chans, 2 byte shorts if(!sndbuf){free(snddat);return NULL;} pcm_handle = open_pcm("hw:0,0"); if(!pcm_handle){free(sndbuf);free(snddat);return NULL;} memset(sndbuf, 0, 2 * sizeof (short) * BUFSAMPS); int nfds = snd_pcm_poll_descriptors_count (pcm_handle); struct pollfd *pfds = (struct pollfd *)alloca(sizeof(struct pollfd) * nfds); snd_pcm_poll_descriptors(pcm_handle, pfds, nfds); while(!bQuit){ if (poll (pfds, nfds, 1000) > 0) { int i; for (i = 0; i < nfds; i++) { if (pfds[i].revents > 0) { if (playback_callback(BUFSAMPS) < BUFSAMPS) snd_pcm_prepare(pcm_handle); } } } } snd_pcm_close(pcm_handle); free(sndbuf);free(snddat); return NULL; }
int main (int argc, char *argv[]) { int nfds, seq_nfds, l1; //int key; //key=0; char *hwdevice; struct pollfd *pfds; /* if (argc < 2) { fprintf(stderr, "LinzerSchnitteMIDI <hw:0,0,1> <attack> <decay> <sustain> <release>\n"); exit(1); } */ initscr(); /* start the curses setup */ atexit(do_endwin); keypad(stdscr, TRUE); noecho(); scrollok(stdscr, TRUE); printw("Welcome to LinzerSchnitte\n"); refresh(); start_color(); init_pair(1, COLOR_RED, COLOR_BLACK); /* end the curses setup */ /* Set default */ hwdevice = "hw:0,0,1"; attack = 0.001; decay = 0.001; sustain = 1; release = 0.001; if (argc > 1) { hwdevice = argv[1]; } /* attack = atof(argv[2]); decay = atof(argv[3]); sustain = atof(argv[4]); release = atof(argv[5]); */ buf = (short *) malloc (2 * sizeof (short) * BUFSIZE); playback_handle = open_pcm(hwdevice); seq_handle = open_seq(); seq_nfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); nfds = snd_pcm_poll_descriptors_count (playback_handle); pfds = (struct pollfd *)alloca(sizeof(struct pollfd) * (seq_nfds + nfds)); snd_seq_poll_descriptors(seq_handle, pfds, seq_nfds, POLLIN); snd_pcm_poll_descriptors (playback_handle, pfds+seq_nfds, nfds); connect2MidiThroughPort(seq_handle); for (l1 = 0; l1 < POLY; note_active[l1++] = 0); while (1) { if (poll (pfds, seq_nfds + nfds, 1000) > 0) { for (l1 = 0; l1 < seq_nfds; l1++) { if (pfds[l1].revents > 0) midi_callback(); } for (l1 = seq_nfds; l1 < seq_nfds + nfds; l1++) { if (pfds[l1].revents > 0) { if (playback_callback(BUFSIZE) < BUFSIZE) { fprintf (stderr, "xrun ! increase buffer \n"); snd_pcm_prepare(playback_handle); } } } } } snd_pcm_close (playback_handle); snd_seq_close (seq_handle); free(buf); return (0); }
/* alsa_init: * ALSA init routine. */ static int alsa_init(int input, int voices) { int ret = 0; char tmp1[128], tmp2[128]; int format = 0; unsigned int numfrags = 0; snd_pcm_uframes_t fragsize; if (input) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported")); return -1; } ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0)); alsa_device = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_device", tmp2), alsa_device); alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_mixer_device", tmp2), alsa_mixer_device); fragsize = get_config_int(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_fragsize", tmp2), 0); numfrags = get_config_int(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_numfrags", tmp2), ALSA_DEFAULT_NUMFRAGS); ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (ret < 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device")); return -1; } snd_mixer_open(&alsa_mixer, 0); if (alsa_mixer && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0 && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0 && snd_mixer_load(alsa_mixer) >= 0) { const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1), uconvert_ascii("alsa_mixer_elem", tmp2), "PCM"); alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer); while (alsa_mixer_elem) { const char *name = snd_mixer_selem_get_name(alsa_mixer_elem); if (strcasecmp(name, alsa_mixer_elem_name) == 0) { snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max); alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255; break; } alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem); } } /* Set format variables. */ alsa_bits = (_sound_bits == 8) ? 8 : 16; alsa_stereo = (_sound_stereo) ? 1 : 0; alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100; alsa_signed = 0; format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8); switch (format) { case SND_PCM_FORMAT_U8: alsa_bits = 8; break; case SND_PCM_FORMAT_U16_NE: if (sizeof(short) != 2) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format")); goto Error; } break; default: ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format")); goto Error; } alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1); if (fragsize == 0) { unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags; fragsize = 1; while (fragsize < size) fragsize <<= 1; } snd_pcm_hw_params_malloc(&hwparams); snd_pcm_sw_params_malloc(&swparams); ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams)); ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)); ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format)); ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1)); ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL)); ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL)); ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL)); ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams)); ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL)); ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL)); TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments); ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams)); ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize)); ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize)); ALSA9_CHECK(snd_pcm_sw_params_set_xfer_align(pcm_handle, swparams, 1)); ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams)); /* Allocate mixing buffer. */ alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size); if (!alsa_bufdata) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer")); goto Error; } /* Initialise mixer. */ digi_alsa.voices = voices; if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate, alsa_stereo, ((alsa_bits == 16) ? 1 : 0), &digi_alsa.voices) != 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer")); goto Error; } snd_pcm_prepare(pcm_handle); pdc = snd_pcm_poll_descriptors_count (pcm_handle); if (pdc <= 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count")); goto Error; } ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc); if (ufds == NULL) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors")); goto Error; } ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc)); poll_next = 0; _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed); /* Add audio interrupt. */ _unix_bg_man->register_func(alsa_update); uszprintf(alsa_desc, sizeof(alsa_desc), get_config_text ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"), alsa_device, alsa_bits, uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1), alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2)); digi_driver->desc = alsa_desc; return 0; Error: if (pcm_handle) { snd_pcm_close(pcm_handle); pcm_handle = NULL; } return -1; }
bool ALSAPCMPlayer::Start(PCMDataSource &_source) { const unsigned new_sample_rate = _source.GetSampleRate(); if ((nullptr != source) && alsa_handle && (source->GetSampleRate() == new_sample_rate)) { /* just change the source / resume playback */ bool success = false; DispatchWait(io_service, [this, &_source, &success]() { bool recovered_from_underrun = false; switch (snd_pcm_state(alsa_handle.get())) { case SND_PCM_STATE_XRUN: if (0 != snd_pcm_prepare(alsa_handle.get())) return; else { recovered_from_underrun = true; success = true; } break; case SND_PCM_STATE_RUNNING: success = true; break; default: return; } if (success) { source = &_source; if (recovered_from_underrun) { const size_t n = buffer_size / channels; const size_t n_read = FillPCMBuffer(buffer.get(), n); if (!WriteFrames(n_read)) { success = false; return; } } if (success) StartEventHandling(); } }); if (success) return true; } Stop(); assert(!alsa_handle); AlsaHandleUniquePtr new_alsa_handle = MakeAlsaHandleUniquePtr(); { const char *alsa_device = ALSAEnv::GetALSADeviceName(); snd_pcm_t *raw_alsa_handle; int alsa_error = snd_pcm_open(&raw_alsa_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, 0); if (alsa_error < 0) { LogFormat("snd_pcm_open(0x%p, \"%s\", SND_PCM_STREAM_PLAYBACK, 0) " "failed: %s", &alsa_handle, alsa_device, snd_strerror(alsa_error)); return false; } new_alsa_handle = MakeAlsaHandleUniquePtr(raw_alsa_handle); assert(new_alsa_handle); } unsigned latency = ALSAEnv::GetALSALatency(); channels = 1; bool big_endian_source = _source.IsBigEndian(); if (!SetParameters(*new_alsa_handle, new_sample_rate, big_endian_source, latency, channels)) return false; snd_pcm_sframes_t n_available = snd_pcm_avail(new_alsa_handle.get()); if (n_available <= 0) { LogFormat("snd_pcm_avail(0x%p) failed: %ld - %s", new_alsa_handle.get(), static_cast<long>(n_available), snd_strerror(static_cast<int>(n_available))); return false; } buffer_size = static_cast<snd_pcm_uframes_t>(n_available * channels); buffer = std::unique_ptr<int16_t[]>(new int16_t[buffer_size]); /* Why does Boost.Asio make it so hard to register a set of of standard poll() descriptors (struct pollfd)? */ int poll_fds_count = snd_pcm_poll_descriptors_count(new_alsa_handle.get()); if (poll_fds_count < 1) { LogFormat("snd_pcm_poll_descriptors_count(0x%p) returned %d", new_alsa_handle.get(), poll_fds_count); return false; } std::unique_ptr<struct pollfd[]> poll_fds( new struct pollfd[poll_fds_count]); BOOST_VERIFY( poll_fds_count == snd_pcm_poll_descriptors(new_alsa_handle.get(), poll_fds.get(), static_cast<unsigned>(poll_fds_count))); for (int i = 0; i < poll_fds_count; ++i) { if ((poll_fds[i].events & POLLIN) || (poll_fds[i].events & POLLPRI)) { read_poll_descs.emplace_back( boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd)); } if (poll_fds[i].events & POLLOUT) { write_poll_descs.emplace_back( boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd)); } } source = &_source; size_t n_read = FillPCMBuffer(buffer.get(), static_cast<size_t>(n_available)); if (0 == n_read) { LogFormat("ALSA PCMPlayer started with data source which " "does not deliver any data"); return false; } if (!WriteFrames(*new_alsa_handle, buffer.get(), static_cast<size_t>(n_available), false)) return false; alsa_handle = std::move(new_alsa_handle); StartEventHandling(); return true; }
AlsaDevice *alsa_device_open(char *device_name, unsigned int rate, int channels, int period) { int dir; int err; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; snd_pcm_uframes_t period_size = period; snd_pcm_uframes_t buffer_size = PERIODS*period; static snd_output_t *jcd_out; AlsaDevice *dev = malloc(sizeof(*dev)); if (!dev) return NULL; dev->device_name = malloc(1+strlen(device_name)); if (!dev->device_name) { free(dev); return NULL; } strcpy(dev->device_name, device_name); dev->channels = channels; dev->period = period; err = snd_output_stdio_attach(&jcd_out, stdout, 0); if ((err = snd_pcm_open (&dev->capture_handle, dev->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev->device_name, snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_any (dev->capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_access (dev->capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_format (dev->capture_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_rate_near (dev->capture_handle, hw_params, &rate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); assert(0); } /*fprintf (stderr, "rate = %d\n", rate);*/ if ((err = snd_pcm_hw_params_set_channels (dev->capture_handle, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); assert(0); } period_size = period; dir = 0; if ((err = snd_pcm_hw_params_set_period_size_near (dev->capture_handle, hw_params, &period_size, &dir)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_periods (dev->capture_handle, hw_params, PERIODS, 0)) < 0) { fprintf (stderr, "cannot set number of periods (%s)\n", snd_strerror (err)); assert(0); } buffer_size = period_size * PERIODS; dir=0; if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->capture_handle, hw_params, &buffer_size)) < 0) { fprintf (stderr, "cannot set buffer time (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params (dev->capture_handle, hw_params)) < 0) { fprintf (stderr, "cannot set capture parameters (%s)\n", snd_strerror (err)); assert(0); } /*snd_pcm_dump_setup(dev->capture_handle, jcd_out);*/ snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { fprintf (stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_current (dev->capture_handle, sw_params)) < 0) { fprintf (stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_avail_min (dev->capture_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set minimum available count (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params (dev->capture_handle, sw_params)) < 0) { fprintf (stderr, "cannot set software parameters (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_open (&dev->playback_handle, dev->device_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", dev->device_name, snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_any (dev->playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_access (dev->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_format (dev->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_rate_near (dev->playback_handle, hw_params, &rate, 0)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); assert(0); } /*fprintf (stderr, "rate = %d\n", rate);*/ if ((err = snd_pcm_hw_params_set_channels (dev->playback_handle, hw_params, channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); assert(0); } period_size = period; dir = 0; if ((err = snd_pcm_hw_params_set_period_size_near (dev->playback_handle, hw_params, &period_size, &dir)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params_set_periods (dev->playback_handle, hw_params, PERIODS, 0)) < 0) { fprintf (stderr, "cannot set number of periods (%s)\n", snd_strerror (err)); assert(0); } buffer_size = period_size * PERIODS; dir=0; if ((err = snd_pcm_hw_params_set_buffer_size_near (dev->playback_handle, hw_params, &buffer_size)) < 0) { fprintf (stderr, "cannot set buffer time (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_hw_params (dev->playback_handle, hw_params)) < 0) { fprintf (stderr, "cannot set playback parameters (%s)\n", snd_strerror (err)); assert(0); } /*snd_pcm_dump_setup(dev->playback_handle, jcd_out);*/ snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { fprintf (stderr, "cannot allocate software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_current (dev->playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot initialize software parameters structure (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_avail_min (dev->playback_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set minimum available count (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params_set_start_threshold (dev->playback_handle, sw_params, period)) < 0) { fprintf (stderr, "cannot set start mode (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_sw_params (dev->playback_handle, sw_params)) < 0) { fprintf (stderr, "cannot set software parameters (%s)\n", snd_strerror (err)); assert(0); } snd_pcm_link(dev->capture_handle, dev->playback_handle); if ((err = snd_pcm_prepare (dev->capture_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); assert(0); } if ((err = snd_pcm_prepare (dev->playback_handle)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); assert(0); } dev->readN = snd_pcm_poll_descriptors_count(dev->capture_handle); dev->writeN = snd_pcm_poll_descriptors_count(dev->playback_handle); dev->read_fd = malloc(dev->readN*sizeof(*dev->read_fd)); /*printf ("descriptors: %d %d\n", dev->readN, dev->writeN);*/ if (snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd, dev->readN) != dev->readN) { fprintf (stderr, "cannot obtain capture file descriptors (%s)\n", snd_strerror (err)); assert(0); } dev->write_fd = malloc(dev->writeN*sizeof(*dev->read_fd)); if (snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd, dev->writeN) != dev->writeN) { fprintf (stderr, "cannot obtain playback file descriptors (%s)\n", snd_strerror (err)); assert(0); } return dev; }
bool QAudioInputPrivate::open( QObject *input ) { // Open the Alsa capture device. bool rc = true; int err; unsigned int freakuency = frequency; if ((err = snd_pcm_open(&handle, m_device.constData(), //"plughw:0,0" SND_PCM_STREAM_CAPTURE, 0/*SND_PCM_ASYNC*/)) < 0) { qWarning( "QAudioInput: snd_pcm_open: error %d", err); rc = false; } else { snd_pcm_hw_params_t *hwparams; // We want non-blocking mode. snd_pcm_nonblock(handle, 1); // Set the desired parameters. snd_pcm_hw_params_alloca(&hwparams); err = snd_pcm_hw_params_any(handle, hwparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_any: err %d", err); } err = snd_pcm_hw_params_set_access(handle, hwparams, access); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_access: err %d",err); } err = snd_pcm_hw_params_set_format(handle, hwparams,format); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_format: err %d",err); } err = snd_pcm_hw_params_set_channels(handle,hwparams,(unsigned int)channels); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_channels: err %d",err); } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err); } if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) { qWarning("QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency); } if ( samplesPerBlock != -1 ) { // Set buffer and period sizes based on the supplied block size. sample_size = (snd_pcm_uframes_t)( samplesPerBlock * channels / 8 ); err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err); } if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) { qWarning( "QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency); } err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } period_time = 1000000 * 256 / frequency; err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err); } } else { // Use the largest buffer and period sizes we can. err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err); } period_time = 1000000 * 256 / frequency; err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err); } } err = snd_pcm_hw_params(handle, hwparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_hw_params: err %d",err); } int dir; unsigned int vval, vval2; snd_pcm_access_t aval; snd_pcm_format_t fval; snd_pcm_subformat_t sval; qLog(QAudioInput) << "PCM handle name = " << snd_pcm_name(handle); qLog(QAudioInput) << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle)); snd_pcm_hw_params_get_access(hwparams,&aval); vval = (unsigned int)aval; if ( (int)vval != (int)access ) { qLog(QAudioInput) << QString("access type not set, want %1 got %2") .arg(snd_pcm_access_name((snd_pcm_access_t)access)) .arg(snd_pcm_access_name((snd_pcm_access_t)vval)); access = (snd_pcm_access_t)vval; } qLog(QAudioInput) << "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 ) { qLog(QAudioInput) << QString("format type not set, want %1 got %2") .arg(snd_pcm_format_name((snd_pcm_format_t)format)) .arg(snd_pcm_format_name((snd_pcm_format_t)vval)); format = (snd_pcm_format_t)vval; } qLog(QAudioInput) << 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(QAudioInput) << 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 ) { qLog(QAudioInput) << QString("channels type not set, want %1 got %2").arg(channels).arg(vval); channels = vval; } qLog(QAudioInput) << "channels = " << vval; snd_pcm_hw_params_get_rate(hwparams, &vval, &dir); if ( (int)vval != (int)frequency ) { qLog(QAudioInput) << QString("frequency type not set, want %1 got %2").arg(frequency).arg(vval); frequency = vval; } qLog(QAudioInput) << "rate =" << vval << " bps"; snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); qLog(QAudioInput) << "period time =" << period_time << " us"; snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir); qLog(QAudioInput) << "period size =" << (int)period_size; snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); qLog(QAudioInput) << "buffer time =" << buffer_time; snd_pcm_hw_params_get_buffer_size(hwparams,(snd_pcm_uframes_t *) &buffer_size); qLog(QAudioInput) << "buffer size =" << (int)buffer_size; snd_pcm_hw_params_get_periods(hwparams, &vval, &dir); qLog(QAudioInput) << "periods per buffer =" << vval; snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2); qLog(QAudioInput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData(); vval = snd_pcm_hw_params_get_sbits(hwparams); qLog(QAudioInput) << "significant bits =" << vval; snd_pcm_hw_params_get_tick_time(hwparams,&vval, &dir); qLog(QAudioInput) << "tick time =" << vval; vval = snd_pcm_hw_params_is_batch(hwparams); qLog(QAudioInput) << "is batch =" << vval; vval = snd_pcm_hw_params_is_block_transfer(hwparams); qLog(QAudioInput) << "is block transfer =" << vval; vval = snd_pcm_hw_params_is_double(hwparams); qLog(QAudioInput) << "is double =" << vval; vval = snd_pcm_hw_params_is_half_duplex(hwparams); qLog(QAudioInput) << "is half duplex =" << vval; vval = snd_pcm_hw_params_is_joint_duplex(hwparams); qLog(QAudioInput) << "is joint duplex =" << vval; vval = snd_pcm_hw_params_can_overrange(hwparams); qLog(QAudioInput) << "can overrange =" << vval; vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams); qLog(QAudioInput) << "can mmap =" << vval; vval = snd_pcm_hw_params_can_pause(hwparams); qLog(QAudioInput) << "can pause =" << vval; vval = snd_pcm_hw_params_can_resume(hwparams); qLog(QAudioInput) << "can resume =" << vval; vval = snd_pcm_hw_params_can_sync_start(hwparams); qLog(QAudioInput) << "can sync start =" << vval; snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_sw_params_current(handle, swparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_current: err %d",err); } err = snd_pcm_sw_params_set_start_threshold(handle,swparams,period_size); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_start_threshold: err %d",err); } err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_avail_min: err %d",err); } err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params_set_xfer_align: err %d",err); } err = snd_pcm_sw_params(handle, swparams); if ( err < 0 ) { qWarning( "QAudioInput: snd_pcm_sw_params: err %d",err); } snd_pcm_prepare(handle); snd_pcm_start(handle); int count = snd_pcm_poll_descriptors_count(handle); pollfd *pfds = new pollfd[count]; snd_pcm_poll_descriptors(handle, pfds, count); for (int i = 0; i < count; ++i) { if ((pfds[i].events & POLLIN) != 0) { notifier = new QSocketNotifier(pfds[i].fd, QSocketNotifier::Read); QObject::connect(notifier, SIGNAL(activated(int)), input, SIGNAL(readyRead())); break; } } if (notifier == NULL) { rc = false; } delete pfds; } return rc; }
static int audio_open(audiodevice_t *dev, chanfmt_t fmt) { audio_alsa09_t *alsa = (audio_alsa09_t *)dev->data_pcm; struct pollfd pfds; snd_pcm_hw_params_t *hwparams; #if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0) snd_pcm_uframes_t len; #else snd_pcm_sframes_t len; #endif int err, periods; if (0 > snd_pcm_open(&alsa->handle, alsa->dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC)) { WARNING("Opening audio device %d failed\n", alsa->dev); goto _err_exit; } snd_pcm_hw_params_alloca(&hwparams); if (0 > snd_pcm_hw_params_any(alsa->handle, hwparams)) { WARNING("param get failed\n"); goto _err_exit; } if (0 > snd_pcm_hw_params_set_access(alsa->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) { WARNING("set access fail\n"); goto _err_exit; } if (0 > snd_pcm_hw_params_set_format(alsa->handle, hwparams, fmt.bit == 16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8)) { WARNING("set format fail\n"); goto _err_exit; } if (0 > snd_pcm_hw_params_set_channels(alsa->handle, hwparams, fmt.ch)) { WARNING("set channel fail\n"); goto _err_exit; } #if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0) int tmp = fmt.rate; err = snd_pcm_hw_params_set_rate_near(alsa->handle, hwparams, &tmp, 0); #else err = snd_pcm_hw_params_set_rate_near(alsa->handle, hwparams, fmt.rate, 0); #endif if (err < 0) { WARNING("set rate fail\n"); goto _err_exit; } if (tmp != fmt.rate) { WARNING("set rate fail\n"); goto _err_exit; } if (0 > snd_pcm_hw_params_set_periods_integer(alsa->handle, hwparams)) { WARNING("set periods fail\n"); goto _err_exit; } periods = 2; if (0 > snd_pcm_hw_params_set_periods_min(alsa->handle, hwparams, &periods, 0)) { WARNING("set priods min fail\n"); goto _err_exit; } if (0 > snd_pcm_hw_params_set_buffer_size(alsa->handle, hwparams, BUFFERSIZE)) { WARNING("set buffer fail\n"); goto _err_exit; } if (0 > snd_pcm_hw_params(alsa->handle, hwparams)) { WARNING("set hw parmas fail\n"); goto _err_exit; } #if SND_LIB_VERSION >= SND_PROTOCOL_VERSION(1,0,0) snd_pcm_hw_params_get_buffer_size(hwparams, &len); #else len = snd_pcm_hw_params_get_buffer_size(hwparams); #endif dev->buf.len = (int)len; snd_pcm_poll_descriptors(alsa->handle, &pfds, 1); dev->fd = pfds.fd; return OK; _err_exit: if (alsa->handle) { snd_pcm_close(alsa->handle); } dev->fd = -1; return NG; }
bool AlsaSource::InitializeAlsa () { bool res = false; int result; AudioStream *stream = NULL; LOG_AUDIO ("AlsaSource::InitializeAlsa (%p) initialized: %i\n", this, initialized); mutex.Lock (); if (initialized) { result = true; goto cleanup; } stream = GetStreamReffed (); if (stream == NULL) { // Shouldn't really happen, but handle this case anyway. LOG_AUDIO ("AlsaSource::Initialize (): trying to initialize an audio device, but there's no audio to play.\n"); goto cleanup; } // Open a pcm device result = snd_pcm_open (&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0 /*SND_PCM_NONBLOCK*/); if (result != 0) { LOG_AUDIO ("AlsaSource::Initialize (): cannot open audio device: %s\n", snd_strerror (result)); pcm = NULL; goto cleanup; } // Configure the hardware if (!SetupHW ()) { LOG_AUDIO ("AlsaSource::Initialize (): could not configure hardware for audio playback\n"); Close (); goto cleanup; } result = snd_pcm_get_params (pcm, &buffer_size, &period_size); if (result != 0) { LOG_AUDIO ("AlsaSource::Initialize (): error while getting parameters: %s\n", snd_strerror (result)); Close (); goto cleanup; } // Get the file descriptors to poll on ndfs = snd_pcm_poll_descriptors_count (pcm); if (ndfs <= 0) { LOG_AUDIO ("AlsaSource::Initialize(): Unable to initialize audio for playback (could not get poll descriptor count).\n"); Close (); goto cleanup; } udfs = (pollfd *) g_malloc0 (sizeof (pollfd) * ndfs); if (snd_pcm_poll_descriptors (pcm, udfs, ndfs) < 0) { LOG_AUDIO ("AlsaSource::Initialize (): Unable to initialize audio for playback (could not get poll descriptors).\n"); Close (); goto cleanup; } LOG_AUDIO ("AlsaSource::Initialize (%p): Succeeded. Buffer size: %lu, period size: %lu\n", this, buffer_size, period_size); res = true; initialized = true; cleanup: mutex.Unlock (); if (stream) stream->unref (); return res; }
int snd_pcm_generic_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) { snd_pcm_generic_t *generic = pcm->private_data; return snd_pcm_poll_descriptors(generic->slave, pfds, space); }
static audio_stream * alsa_create_stream(audio_stream_direction direction, unsigned int sample_rate, unsigned int sample_frame_count, const char *pcm_name) { audio_stream *as; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; int dir; if (!g_atomic_int_get(&audio_thread_started)) { pthread_barrier_init(&stream_list_update_barrier, NULL, 2); pthread_create(&audio_thread_id, NULL, audio_thread, NULL); g_atomic_int_set(&audio_thread_started, 1); pthread_barrier_wait(&stream_list_update_barrier); } as = calloc(1, sizeof(*as)); if (!as) goto err; as->sample_frame_count = sample_frame_count; g_atomic_int_set(&as->paused, 1); #define CHECK_A(funcname, params) \ do { \ int errcode___ = funcname params; \ if (errcode___ < 0) { \ trace_error("%s, " #funcname ", %s\n", __func__, snd_strerror(errcode___)); \ goto err; \ } \ } while (0) if (direction == STREAM_PLAYBACK) CHECK_A(snd_pcm_open, (&as->pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)); else CHECK_A(snd_pcm_open, (&as->pcm, pcm_name, SND_PCM_STREAM_CAPTURE, 0)); CHECK_A(snd_pcm_hw_params_malloc, (&hw_params)); CHECK_A(snd_pcm_hw_params_any, (as->pcm, hw_params)); CHECK_A(snd_pcm_hw_params_set_access, (as->pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)); CHECK_A(snd_pcm_hw_params_set_format, (as->pcm, hw_params, SND_PCM_FORMAT_S16_LE)); dir = 0; unsigned int rate = sample_rate; CHECK_A(snd_pcm_hw_params_set_rate_near, (as->pcm, hw_params, &rate, &dir)); const int channel_count = (direction == STREAM_PLAYBACK) ? 2 : 1; CHECK_A(snd_pcm_hw_params_set_channels, (as->pcm, hw_params, channel_count)); unsigned int period_time = (long long)sample_frame_count * 1000 * 1000 / sample_rate; period_time = CLAMP(period_time, 1000 * (unsigned int)config.audio_buffer_min_ms, 1000 * (unsigned int)config.audio_buffer_max_ms); dir = 1; CHECK_A(snd_pcm_hw_params_set_period_time_near, (as->pcm, hw_params, &period_time, &dir)); unsigned int buffer_time = 4 * period_time; dir = 1; CHECK_A(snd_pcm_hw_params_set_buffer_time_near, (as->pcm, hw_params, &buffer_time, &dir)); dir = 0; CHECK_A(snd_pcm_hw_params_get_buffer_time, (hw_params, &buffer_time, &dir)); CHECK_A(snd_pcm_hw_params, (as->pcm, hw_params)); snd_pcm_hw_params_free(hw_params); CHECK_A(snd_pcm_sw_params_malloc, (&sw_params)); CHECK_A(snd_pcm_sw_params_current, (as->pcm, sw_params)); CHECK_A(snd_pcm_sw_params, (as->pcm, sw_params)); CHECK_A(snd_pcm_prepare, (as->pcm)); snd_pcm_sw_params_free(sw_params); CHECK_A(snd_pcm_prepare, (as->pcm)); if (direction == STREAM_CAPTURE) CHECK_A(snd_pcm_start, (as->pcm)); as->nfds = snd_pcm_poll_descriptors_count(as->pcm); as->fds = calloc(as->nfds, sizeof(struct pollfd)); if (!as->fds) { trace_error("%s, memory allocation failure\n", __func__); goto err; } snd_pcm_poll_descriptors(as->pcm, as->fds, as->nfds); g_hash_table_insert(active_streams_ht, as, GINT_TO_POINTER(1)); for (uintptr_t k = 0; k < as->nfds; k ++) g_hash_table_insert(stream_by_fd_ht, GINT_TO_POINTER(as->fds[k].fd), as); wakeup_audio_thread(); #undef CHECK_A return as; err: free(as); return NULL; }
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; }
bool WaveRecorder::init(uint32_t samples_per_sec, uint32_t bits_per_sample, uint32_t channels, uint32_t frame_size) { const char* pcm_device = "default"; snd_pcm_format_t format; int err; _frame_size = frame_size; switch (bits_per_sample) { case 8: format = SND_PCM_FORMAT_S8; break; case 16: format = SND_PCM_FORMAT_S16_LE; break; default: return false; } if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { LOG_ERROR("cannot open audio record device %s %s", pcm_device, snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_malloc(&_hw_params)) < 0) { LOG_ERROR("cannot allocate hardware parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_malloc(&_sw_params)) < 0) { LOG_ERROR("cannot allocate software parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_any(_pcm, _hw_params)) < 0) { LOG_ERROR("cannot initialize hardware parameter structure %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_rate_resample(_pcm, _hw_params, 1)) < 0) { LOG_ERROR("cannot set rate resample %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_access(_pcm, _hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { LOG_ERROR("cannot set access type %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_rate(_pcm, _hw_params, samples_per_sec, 0)) < 0) { LOG_ERROR("cannot set sample rate %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_channels(_pcm, _hw_params, channels)) < 0) { LOG_ERROR("cannot set channel count %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_format(_pcm, _hw_params, format)) < 0) { LOG_ERROR("cannot set sample format %s", snd_strerror(err)); return false; } int direction = 0; snd_pcm_uframes_t buffer_size = (samples_per_sec * 160 / 1000) / frame_size * frame_size; if ((err = snd_pcm_hw_params_set_buffer_size_near(_pcm, _hw_params, &buffer_size)) < 0) { LOG_ERROR("cannot set buffer size %s", snd_strerror(err)); return false; } snd_pcm_uframes_t period_size = frame_size; if ((err = snd_pcm_hw_params_set_period_size_near(_pcm, _hw_params, &period_size, &direction)) < 0) { LOG_ERROR("cannot set period size near %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params(_pcm, _hw_params)) < 0) { LOG_ERROR("cannot set parameters %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_current(_pcm, _sw_params)) < 0) { LOG_ERROR("cannot get current sw parameters %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params_set_start_threshold(_pcm, _sw_params, frame_size)) < 0) { LOG_ERROR("cannot set start threshold %s", snd_strerror(err)); return false; } if ((err = snd_pcm_sw_params(_pcm, _sw_params)) < 0) { LOG_ERROR("cannot set sw parameters %s", snd_strerror(err)); return false; } struct pollfd pfd; if ((err = snd_pcm_poll_descriptors(_pcm, &pfd, 1)) < 0) { LOG_ERROR("cannot get poll ID %s", snd_strerror(err)); return false; } _event_trigger = new WaveRecorder::EventTrigger(*this, pfd.fd); _client.add_event_source(*_event_trigger); return true; }
static gboolean alsa_open (void *dp) { alsa_driver * const d = dp; gint mf, err, pers; if(pcm_open_and_load_hwparams(d) < 0) goto out; // --- // Set non-blocking mode. // --- d->outtime = 0; // -- // Set channel parameters // -- if((err = snd_pcm_hw_params_set_access(d->soundfd, d->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){ alsa_error(N_("Unable to set access"), err); goto out; } if((err = snd_pcm_hw_params_set_format(d->soundfd, d->hwparams, (d->bits - 8) ? d->signedness16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U16 : d->signedness8 ? SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_U8) < 0)) { alsa_error(N_("Unable to set audio format"), err); goto out; } /* Handle endianess aspects. TODO! */ switch(d->bits) { case 16: mf = d->signedness16 ? ST_MIXER_FORMAT_S16_LE : ST_MIXER_FORMAT_U16_LE; break; case 8: default: mf = d->signedness8 ? ST_MIXER_FORMAT_S8 : ST_MIXER_FORMAT_U8; break; } if((err = snd_pcm_hw_params_set_channels(d->soundfd, d->hwparams, d->stereo + 1)) < 0) { alsa_error(N_("Unable to set channels number"), err); goto out; } if((d->stereo)) { mf |= ST_MIXER_FORMAT_STEREO; } d->mf = mf; d->p_mixfreq = d->playrate; if ((err = snd_pcm_hw_params_set_rate_near(d->soundfd, d->hwparams, &(d->p_mixfreq), NULL)) < 0) { alsa_error(N_("Unable to set sample rate"), err); goto out; } if(snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size) < 0) { /* Some soundcards report wrong maximal buffer size (maybe alsa bug). So we should try to downscale its value before the reporting an error. The spinbutton still may display the wrong number, but actually the correct value will be implemented.*/ while((--d->buffer_size) >= 8) if(!snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size)) break; if(d->buffer_size < 8) { error_error(N_("Unable to set appropriate buffer size")); goto out; } } pers = 1 << d->num_periods; if ((err = snd_pcm_hw_params_set_periods_near(d->soundfd, d->hwparams, &pers, NULL)) < 0) { alsa_error(N_("Unable to set periods number"), err); goto out; } if ((err = snd_pcm_hw_params_get_period_size(d->hwparams, &(d->p_fragsize), NULL)) < 0) { alsa_error(N_("Unable to get period size"), err); goto out; } if((err = snd_pcm_hw_params(d->soundfd, d->hwparams))) { alsa_error(N_("Error setting hw parameters"), err); goto out; } /* The following piece of code is directly c_n_p'ed from the ALSA pcm example (whith a little adopting) */ /* get the current swparams */ err = snd_pcm_sw_params_current(d->soundfd, d->swparams); if (err < 0) { alsa_error(N_("Unable to determine current swparams for playback"), err); goto out; } /* start the transfer when the buffer is full */ err = snd_pcm_sw_params_set_start_threshold(d->soundfd, d->swparams, d->p_fragsize); if (err < 0) { alsa_error(N_("Unable to set start threshold mode for playback"), err); goto out; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(d->soundfd, d->swparams, d->p_fragsize); if (err < 0) { alsa_error(N_("Unable to set avail min for playback"), err); goto out; } /* align all transfers to 1 sample */ err = snd_pcm_sw_params_set_xfer_align(d->soundfd, d->swparams, 1); if (err < 0) { alsa_error(N_("Unable to set transfer align for playback"), err); goto out; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(d->soundfd, d->swparams); if (err < 0) { alsa_error(N_("Unable to set sw params for playback"), err); goto out; } err = snd_pcm_prepare(d->soundfd); if (err < 0) { alsa_error(N_("Unable to prepare playback"), err); goto out; } // --- // Get buffering parameters // --- if(d->verbose) snd_pcm_dump(d->soundfd, d->output); d->sndbuf = calloc((d->stereo + 1) * (d->bits / 8), d->p_fragsize); d->pfd = malloc(sizeof(struct pollfd)); if ((err = snd_pcm_poll_descriptors(d->soundfd, d->pfd, 1)) < 0) { alsa_error(N_("Unable to obtain poll descriptors for playback"), err); goto out; } d->polltag = audio_poll_add(d->pfd->fd, GDK_INPUT_WRITE, alsa_poll_ready_playing, d); d->playtime = 0; d->firstpoll = TRUE; return TRUE; out: alsa_release(dp); return FALSE; }
int cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name, cubeb_stream_params stream_params, unsigned int latency, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { cubeb_stream * stm; int r; snd_pcm_format_t format; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; assert(context); assert(stream); if (stream_params.rate < 1 || stream_params.rate > 192000 || stream_params.channels < 1 || stream_params.channels > 32 || latency < 1 || latency > 2000) { return CUBEB_ERROR_INVALID_FORMAT; } switch (stream_params.format) { case CUBEB_SAMPLE_S16LE: format = SND_PCM_FORMAT_S16_LE; break; case CUBEB_SAMPLE_S16BE: format = SND_PCM_FORMAT_S16_BE; break; case CUBEB_SAMPLE_FLOAT32LE: format = SND_PCM_FORMAT_FLOAT_LE; break; case CUBEB_SAMPLE_FLOAT32BE: format = SND_PCM_FORMAT_FLOAT_BE; break; default: return CUBEB_ERROR_INVALID_FORMAT; } stm = calloc(1, sizeof(*stm)); assert(stm); stm->context = context; stm->data_callback = data_callback; stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->params = stream_params; r = pthread_mutex_init(&stm->lock, NULL); assert(r == 0); r = pthread_cond_init(&stm->cond, NULL); assert(r == 0); r = cubeb_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK); if (r < 0) { cubeb_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, latency * 1000); if (r < 0) { /* XXX: return format error if necessary */ cubeb_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_get_params(stm->pcm, &buffer_size, &period_size); assert(r == 0); fprintf(stderr, "b=%u p=%u\n", buffer_size, period_size); /* set up poll infrastructure */ stm->n_descriptors = snd_pcm_poll_descriptors_count(stm->pcm); assert(stm->n_descriptors > 0); stm->descriptors = calloc(stm->n_descriptors, sizeof(*stm->descriptors)); assert(stm->descriptors); r = snd_pcm_poll_descriptors(stm->pcm, stm->descriptors, stm->n_descriptors); assert(r == stm->n_descriptors); r = snd_pcm_pause(stm->pcm, 1); #if 0 assert(r == 0); #endif stm->state = CUBEB_STREAM_STATE_INACTIVE; *stream = stm; return CUBEB_OK; }
static int alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, cubeb_stream_params stream_params, unsigned int latency, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { cubeb_stream * stm; int r; snd_pcm_format_t format; assert(ctx && stream); *stream = NULL; switch (stream_params.format) { case CUBEB_SAMPLE_S16LE: format = SND_PCM_FORMAT_S16_LE; break; case CUBEB_SAMPLE_S16BE: format = SND_PCM_FORMAT_S16_BE; break; case CUBEB_SAMPLE_FLOAT32LE: format = SND_PCM_FORMAT_FLOAT_LE; break; case CUBEB_SAMPLE_FLOAT32BE: format = SND_PCM_FORMAT_FLOAT_BE; break; default: return CUBEB_ERROR_INVALID_FORMAT; } pthread_mutex_lock(&ctx->mutex); if (ctx->active_streams >= CUBEB_STREAM_MAX) { pthread_mutex_unlock(&ctx->mutex); return CUBEB_ERROR; } ctx->active_streams += 1; pthread_mutex_unlock(&ctx->mutex); stm = calloc(1, sizeof(*stm)); assert(stm); stm->context = ctx; stm->data_callback = data_callback; stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->params = stream_params; stm->state = INACTIVE; r = pthread_mutex_init(&stm->mutex, NULL); assert(r == 0); r = alsa_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK, ctx->local_config); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274. Only resort to this hack if the handle_underrun workaround failed. */ if (!ctx->local_config && ctx->is_pa) { latency = latency < 500 ? 500 : latency; } r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, latency * 1000); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR_INVALID_FORMAT; } r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &stm->period_size); assert(r == 0); stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm); assert(stm->nfds > 0); stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd)); assert(stm->saved_fds); r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds); assert((nfds_t) r == stm->nfds); r = pthread_cond_init(&stm->cond, NULL); assert(r == 0); if (alsa_register_stream(ctx, stm) != 0) { alsa_stream_destroy(stm); return CUBEB_ERROR; } *stream = stm; return CUBEB_OK; }
static int wait( PaAlsaStream *stream ) { int need_capture; int need_playback; int capture_avail = INT_MAX; int playback_avail = INT_MAX; int common_avail; if( stream->pcm_capture ) need_capture = 1; else need_capture = 0; if( stream->pcm_playback ) need_playback = 1; else need_playback = 0; while( need_capture || need_playback ) { int playback_pfd_offset; int total_fds = 0; /* if the main thread has requested that we stop, do so now */ pthread_testcancel(); /*PA_DEBUG(("still polling...\n")); if( need_capture ) PA_DEBUG(("need capture.\n")); if( need_playback ) PA_DEBUG(("need playback.\n")); */ /* get the fds, packing all applicable fds into a single array, * so we can check them all with a single poll() call */ if( need_capture ) { snd_pcm_poll_descriptors( stream->pcm_capture, stream->pfds, stream->capture_nfds ); total_fds += stream->capture_nfds; } if( need_playback ) { playback_pfd_offset = total_fds; snd_pcm_poll_descriptors( stream->pcm_playback, stream->pfds + playback_pfd_offset, stream->playback_nfds ); total_fds += stream->playback_nfds; } /* now poll on the combination of playback and capture fds. * TODO: handle interrupt and/or failure */ poll( stream->pfds, total_fds, 1000 ); /* check the return status of our pfds */ if( need_capture ) { short revents; snd_pcm_poll_descriptors_revents( stream->pcm_capture, stream->pfds, stream->capture_nfds, &revents ); if( revents == POLLIN ) need_capture = 0; } if( need_playback ) { short revents; snd_pcm_poll_descriptors_revents( stream->pcm_playback, stream->pfds + playback_pfd_offset, stream->playback_nfds, &revents ); //if( revents & POLLOUT ) //if( revents & POLLERR ) // PA_DEBUG(("polling error!")); if( revents == POLLOUT ) need_playback = 0; } } /* we have now established that there are buffers ready to be * operated on. Now determine how many frames are available. */ if( stream->pcm_capture ) capture_avail = snd_pcm_avail_update( stream->pcm_capture ); if( stream->pcm_playback ) playback_avail = snd_pcm_avail_update( stream->pcm_playback ); common_avail = MIN(capture_avail, playback_avail); common_avail -= common_avail % stream->frames_per_period; return common_avail; }