void QAudioOutputPrivate::resume() { if(deviceState == QAudio::SuspendedState) { int err = 0; if(handle) { err = snd_pcm_prepare( handle ); if(err < 0) xrun_recovery(err); err = snd_pcm_start(handle); if(err < 0) xrun_recovery(err); bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); } resuming = true; if(pullMode) deviceState = QAudio::ActiveState; else deviceState = QAudio::IdleState; errorState = QAudio::NoError; timer->start(period_time/1000); emit stateChanged(deviceState); } }
static void ALSA_Update(void) { int err; if (!enabled) return; if (bytes_written == 0 || bytes_played == bytes_written) { bytes_written = VC_WriteBytes(audiobuffer,period_size * global_frame_size); bytes_played = 0; } while (bytes_played < bytes_written) { err = alsa_pcm_writei(pcm_h, &audiobuffer[bytes_played], (bytes_written - bytes_played) / global_frame_size); if (err == -EAGAIN) continue; if (err < 0) { if ((err = xrun_recovery(pcm_h, err)) < 0) { _mm_errno = MMERR_ALSA_PCM_RECOVER; enabled = 0; dbgprint(stderr, "Write error: %s\n", alsa_strerror(err)); } break; } bytes_played += err * global_frame_size; } }
static int write_loop(snd_pcm_t *handle, signed short *samples, snd_pcm_channel_area_t *areas) { double phase = 0; signed short *ptr; int err, cptr; while (1) { generate_sine(areas, 0, period_size, &phase); ptr = samples; cptr = period_size; while (cptr > 0) { err = snd_pcm_writei(handle, ptr, cptr); if (err == -EAGAIN) continue; if (err < 0) { if (xrun_recovery(handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } break; /* skip one period */ } ptr += err * channels; cptr -= err; } } }
/* alsa_update: * Updates main buffer in case ALSA is ready. */ static void alsa_update(int threaded) { unsigned short revents; if (poll_next) { poll(ufds, pdc, 0); snd_pcm_poll_descriptors_revents(pcm_handle, ufds, pdc, &revents); if (revents & POLLERR) { if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN || snd_pcm_state(pcm_handle) == SND_PCM_STATE_SUSPENDED) { int err = snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE; if (xrun_recovery(pcm_handle, err) < 0) { fprintf(stderr, "Write error: %s\n", snd_strerror(err)); } poll_next = 0; } else { fprintf(stderr, "Wait for poll failed\n"); } return; } if (!(revents & POLLOUT)) return; } alsa_mix(); }
static guint gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) { GstAlsaSink *alsa; gint err; gint cptr; gint16 *ptr = data; alsa = GST_ALSA_SINK (asink); if (alsa->iec958 && alsa->need_swap) { guint i; GST_DEBUG_OBJECT (asink, "swapping bytes"); for (i = 0; i < length / 2; i++) { ptr[i] = GUINT16_SWAP_LE_BE (ptr[i]); } } GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length); cptr = length / alsa->bytes_per_sample; GST_ALSA_SINK_LOCK (asink); while (cptr > 0) { /* start by doing a blocking wait for free space. Set the timeout * to 4 times the period time */ err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000)); if (err < 0) { GST_DEBUG_OBJECT (asink, "wait error, %d", err); } else { GST_DELAY_SINK_LOCK (asink); err = snd_pcm_writei (alsa->handle, ptr, cptr); GST_DELAY_SINK_UNLOCK (asink); } GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr); if (err < 0) { GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err)); if (err == -EAGAIN) { continue; } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { goto write_error; } continue; } ptr += snd_pcm_frames_to_bytes (alsa->handle, err); cptr -= err; } GST_ALSA_SINK_UNLOCK (asink); return length - (cptr * alsa->bytes_per_sample); write_error: { GST_ALSA_SINK_UNLOCK (asink); return length; /* skip one period */ } }
static void ALSA_Update(void) { int err; { if (bytes_written == 0 || bytes_played == bytes_written) { bytes_written = VC_WriteBytes(audiobuffer,buffer_size_in_frames * global_frame_size); bytes_played = 0; } while (bytes_played < bytes_written) { err = alsa_pcm_writei(pcm_h, &audiobuffer[bytes_played], (bytes_written - bytes_played) / global_frame_size); if (err == -EAGAIN) { continue; } if (err < 0) { if ((err = xrun_recovery(pcm_h, err)) < 0) { printf("Write error: %s\n", alsa_strerror(err)); exit(-1); } break; } bytes_played += err * global_frame_size; } } }
void write( const char *data, qint64 len ) { if ( !handle ) return; int count=0; qLog(QAudioOutput)<<"frames to write out = "<< snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes"; while ( len > 0 ) { int err=0; int frames = snd_pcm_bytes_to_frames( handle, (int)len ); #ifdef ALSA_USE_AVAILABLE if(frames < (int)period_size) return; int available = snd_pcm_avail_update(handle); qLog(QAudioOutput) <<"available space = "<<available; if(available == 0) { while(available < frames) { snd_pcm_wait(handle,period_size/1000); usleep(period_size*10); available = snd_pcm_avail_update(handle); qLog(QAudioOutput) <<"->available space = "<<available; count++; if((count > 5)||(available < 0)) return; } } #endif err = snd_pcm_writei( handle, data, frames ); // Handle errors if ( err >= 0 ) { if(err == 0) count++; int bytes = snd_pcm_frames_to_bytes( handle, err ); qLog(QAudioOutput) << QString("write out = %1").arg(bytes).toLatin1().constData(); data += bytes; len -= bytes; } else { count++; qLog(QAudioOutput) <<"err = "<<err; err = xrun_recovery(err); } if(count > 5) { qLog(QAudioOutput) <<"failing to write, close() and re-open() to try and recover!"; close(); open(); snd_pcm_prepare(handle); break; } } }
static int verify_state(snd_pcm_t *handle) { snd_pcm_state_t state = psnd_pcm_state(handle); if(state == SND_PCM_STATE_DISCONNECTED) return -ENODEV; if(state == SND_PCM_STATE_XRUN) { int err = xrun_recovery(handle, -EPIPE); if(err < 0) return err; } else if(state == SND_PCM_STATE_SUSPENDED) { int err = xrun_recovery(handle, -ESTRPIPE); if(err < 0) return err; } return state; }
static GstClockTime gst_alsasrc_get_timestamp (GstAlsaSrc * asrc) { snd_pcm_status_t *status; snd_htimestamp_t tstamp; GstClockTime timestamp; snd_pcm_uframes_t avail; gint err = -EPIPE; if (G_UNLIKELY (!asrc)) { GST_ERROR_OBJECT (asrc, "No alsa handle created yet !"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status_malloc (&status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status_malloc failed"); return GST_CLOCK_TIME_NONE; } if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); return GST_CLOCK_TIME_NONE; } /* in case an xrun condition has occured we need to handle this */ if (snd_pcm_status_get_state (status) != SND_PCM_STATE_RUNNING) { if (xrun_recovery (asrc, asrc->handle, err) < 0) { GST_WARNING_OBJECT (asrc, "Could not recover from xrun condition !"); } /* reload the status alsa status object, since recovery made it invalid */ if (G_UNLIKELY (snd_pcm_status (asrc->handle, status) != 0)) { GST_ERROR_OBJECT (asrc, "snd_pcm_status failed"); } } /* get high resolution time stamp from driver */ snd_pcm_status_get_htstamp (status, &tstamp); timestamp = GST_TIMESPEC_TO_TIME (tstamp); /* max available frames sets the depth of the buffer */ avail = snd_pcm_status_get_avail (status); /* calculate the timestamp of the next sample to be read */ timestamp -= gst_util_uint64_scale_int (avail, GST_SECOND, asrc->rate); /* compensate for the fact that we really need the timestamp of the * previously read data segment */ timestamp -= asrc->period_time * 1000; snd_pcm_status_free (status); GST_LOG_OBJECT (asrc, "ALSA timestamp : %" GST_TIME_FORMAT ", delay %lu", GST_TIME_ARGS (timestamp), avail); return timestamp; }
static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length, GstClockTime * timestamp) { GstAlsaSrc *alsa; gint err; gint cptr; guint8 *ptr = data; alsa = GST_ALSA_SRC (asrc); cptr = length / alsa->bpf; GST_ALSA_SRC_LOCK (asrc); while (cptr > 0) { GST_DELAY_SRC_LOCK (asrc); err = snd_pcm_readi (alsa->handle, ptr, cptr); GST_DELAY_SRC_UNLOCK (asrc); if (err < 0) { if (err == -EAGAIN) { GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err)); continue; } else if (err == -ENODEV) { goto device_disappeared; } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { goto read_error; } continue; } ptr += snd_pcm_frames_to_bytes (alsa->handle, err); cptr -= err; } GST_ALSA_SRC_UNLOCK (asrc); /* if driver timestamps are enabled we need to return this here */ if (alsa->driver_timestamps && timestamp) *timestamp = gst_alsasrc_get_timestamp (alsa); return length - (cptr * alsa->bpf); read_error: { GST_ALSA_SRC_UNLOCK (asrc); return length; /* skip one period */ } device_disappeared: { GST_ELEMENT_ERROR (asrc, RESOURCE, READ, (_("Error recording from audio device. " "The device has been disconnected.")), (NULL)); GST_ALSA_SRC_UNLOCK (asrc); return (guint) - 1; } }
static int write_loop(snd_pcm_t *handle) { double phase = 0; signed short *ptr; int err, cptr; struct async_private_data data; snd_async_handler_t *ahandler; size_t data_len; signed short *samples_buf_play; samples_buf_play = malloc(910*2); FILE* file_playback = fopen("file_playback","rb"); FILE* file_dump = fopen("file_dump","wb"); if(file_playback== NULL) { printf("file open err check the file please\r\n"); return 0; } err = snd_async_add_pcm_handler(&ahandler, handle, play_callback, &data); if (err < 0) { printf("Unable to register async handler\n"); exit(EXIT_FAILURE); } while (1) { data_len = fread(samples_buf_play,2,910,file_playback); fwrite(samples_buf_play,2,data_len,file_dump); if(data_len != 910) { printf("the data is not enough %d\r\n",data_len ); return 0; } err = snd_pcm_writei(handle, samples_buf_play,910); if (err < 0) { if (xrun_recovery(handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } break; /* skip one period */ } } }
static int alsa_bufferspace(void) { int err; snd_pcm_sframes_t delay; if ((err = snd_pcm_delay(handle, &delay)) < 0) { if ((err = xrun_recovery(handle, err)) < 0) { log_message(LOG_DEFAULT, "Delay error: %s", snd_strerror(err)); } return alsa_bufsize; } return alsa_bufsize - delay; }
void QAlsaAudioInput::resume() { if(deviceState == QAudio::SuspendedState) { int err = 0; if(handle) { err = snd_pcm_prepare( handle ); if(err < 0) xrun_recovery(err); err = snd_pcm_start(handle); if(err < 0) xrun_recovery(err); bytesAvailable = buffer_size; } resuming = true; deviceState = QAudio::ActiveState; int chunks = buffer_size/period_size; timer->start(period_time*chunks/2000); emit stateChanged(deviceState); } }
static void * alsa_thread(void *arg) { gint16 *ptr; int err, cptr; guint8 *buf; sfx_pcm_device_t *self = (sfx_pcm_device_t *) arg; buf = (guint8 *) malloc(period_size * frame_size); while (run_thread) { ptr = (gint16 *) buf; cptr = period_size; sci_gettime(&last_callback_secs, &last_callback_usecs); self->timer->block(); if (alsa_sfx_timer_callback) alsa_sfx_timer_callback(alsa_sfx_timer_data); self->timer->unblock(); sfx_audbuf_read(&audio_buffer, buf, period_size); while (cptr > 0) { err = snd_pcm_writei(handle, ptr, cptr); if (err == -EAGAIN) continue; if (err < 0) { if (xrun_recovery(handle, err) < 0) { fprintf(stderr, "[SND:ALSA] Write error: %s\n", snd_strerror(err)); run_thread = 0; } break; /* skip one period */ } ptr += err * channels; cptr -= err; } } free(buf); return NULL; }
// returns -1 on error int DAUDIO_Read(void* id, char* data, int byteSize) { AlsaPcmInfo* info = (AlsaPcmInfo*) id; int ret, count; snd_pcm_sframes_t frameSize, readFrames; TRACE1("> DAUDIO_Read %d bytes\n", byteSize); /*TRACE3(" info=%p, data=%p, byteSize=%d\n", (void*) info, (void*) data, (int) byteSize); TRACE2(" info->frameSize=%d, info->handle=%p\n", (int) info->frameSize, (void*) info->handle); */ /* sanity */ if (byteSize <= 0 || info->frameSize <= 0) { ERROR2(" DAUDIO_Read: byteSize=%d, frameSize=%d!\n", (int) byteSize, (int) info->frameSize); TRACE0("< DAUDIO_Read returning -1\n"); return -1; } count = 2; // maximum number of trials to recover from error //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); do { readFrames = snd_pcm_readi(info->handle, (void*) data, (snd_pcm_uframes_t) frameSize); if (readFrames < 0) { ret = xrun_recovery(info, (int) readFrames); if (ret <= 0) { TRACE1("DAUDIO_Read: xrun recovery returned %d -> return.\n", ret); return ret; } if (count-- <= 0) { ERROR0("DAUDIO_Read: too many attempts to recover from xrun/suspend\n"); return -1; } } else { break; } } while (TRUE); //ret = snd_pcm_frames_to_bytes(info->handle, readFrames); ret = (int) (readFrames * info->frameSize); TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); return ret; }
qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) { // Write out some audio data if ( !handle ) return 0; #ifdef DEBUG_AUDIO qDebug()<<"frames to write out = "<< snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes"; #endif int frames, err; int space = bytesFree(); if(len < space) { // Just write it frames = snd_pcm_bytes_to_frames( handle, (int)len ); err = snd_pcm_writei( handle, data, frames ); } else { // Only write space worth frames = snd_pcm_bytes_to_frames( handle, (int)space ); err = snd_pcm_writei( handle, data, frames ); } if(err > 0) { totalTimeValue += err; resuming = false; errorState = QAudio::NoError; if (deviceState != QAudio::ActiveState) { deviceState = QAudio::ActiveState; emit stateChanged(deviceState); } return snd_pcm_frames_to_bytes( handle, err ); } else err = xrun_recovery(err); if(err < 0) { close(); errorState = QAudio::FatalError; emit errorChanged(errorState); deviceState = QAudio::StoppedState; emit stateChanged(deviceState); } return 0; }
static int alsa_write(SWORD *pbuf, size_t nr) { int err; nr /= alsa_channels; while (nr > 0) { err = snd_pcm_writei(handle, pbuf, nr); if (err == -EAGAIN) { log_message(LOG_DEFAULT, "Write error: %s", snd_strerror(err)); continue; } else if (err < 0 && (err = xrun_recovery(handle, err)) < 0) { log_message(LOG_DEFAULT, "Write error: %s", snd_strerror(err)); return 1; } pbuf += err * alsa_channels; nr -= err; } return 0; }
// returns -1 on error int DAUDIO_Write(void* id, char* data, int byteSize) { AlsaPcmInfo* info = (AlsaPcmInfo*) id; int ret, count; snd_pcm_sframes_t frameSize, writtenFrames; TRACE1("> DAUDIO_Write %d bytes\n", byteSize); /* sanity */ if (byteSize <= 0 || info->frameSize <= 0) { ERROR2(" DAUDIO_Write: byteSize=%d, frameSize=%d!\n", (int) byteSize, (int) info->frameSize); TRACE0("< DAUDIO_Write returning -1\n"); return -1; } count = 2; // maximum number of trials to recover from underrun //frameSize = snd_pcm_bytes_to_frames(info->handle, byteSize); frameSize = (snd_pcm_sframes_t) (byteSize / info->frameSize); do { writtenFrames = snd_pcm_writei(info->handle, (const void*) data, (snd_pcm_uframes_t) frameSize); if (writtenFrames < 0) { ret = xrun_recovery(info, (int) writtenFrames); if (ret <= 0) { TRACE1("DAUDIO_Write: xrun recovery returned %d -> return.\n", ret); return ret; } if (count-- <= 0) { ERROR0("DAUDIO_Write: too many attempts to recover from xrun/suspend\n"); return -1; } } else { break; } } while (TRUE); //ret = snd_pcm_frames_to_bytes(info->handle, writtenFrames); ret = (int) (writtenFrames * info->frameSize); TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); return ret; }
static int play(struct audio_play *play) { int err, len; char *ptr; ptr = buf; len = play->nsamples; audio_pcm(ptr, len, play->samples[0], play->samples[1], play->mode, play->stats); while (len > 0) { err = snd_pcm_mmap_writei(alsa_handle, ptr, len); if (err == -EAGAIN) continue; if (err < 0) { if (xrun_recovery(alsa_handle, err) < 0) { audio_error = snd_strerror(err); return -1; } break; } len -= err; ptr += err * sample_size; } return 0; }
/* alsa_mix * Mix and send some samples to ALSA. */ static void alsa_mix(void) { int ret, samples = alsa_bufsize; unsigned char *ptr = alsa_bufdata; while (samples > 0) { ret = snd_pcm_writei(pcm_handle, ptr, samples); if (ret == -EAGAIN) continue; if (ret < 0) { if (xrun_recovery(pcm_handle, ret) < 0) fprintf(stderr, "Write error: %s\n", snd_strerror(ret)); poll_next = 0; break; /* skip one period */ } if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_RUNNING) poll_next = 1; samples -= ret; ptr += ret * alsa_sample_size; } _mix_some_samples((uintptr_t)alsa_bufdata, 0, alsa_signed); }
bool QAlsaAudioInput::deviceReady() { if(pullMode) { // reads some audio data and writes it to QIODevice read(0, buffer_size); } else { // emits readyRead() so user will call read() on QIODevice to get some audio data AlsaInputPrivate* a = qobject_cast<AlsaInputPrivate*>(audioSource); a->trigger(); } bytesAvailable = checkBytesReady(); if(deviceState != QAudio::ActiveState) return true; if (bytesAvailable < 0) { // bytesAvailable as negative is error code, try to recover from it. xrun_recovery(bytesAvailable); bytesAvailable = checkBytesReady(); if (bytesAvailable < 0) { // recovery failed must stop and set error. close(); errorState = QAudio::IOError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); return 0; } } if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { emit notify(); elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; timeStamp.restart(); } return true; }
static void *sound_play(void *args) { char path[256]; int samplerate; int err; snd_pcm_t *playback_handle; snd_pcm_hw_params_t *hw_params; FILE *fp; db_msg("prepare play sound...\n"); if (script_fetch("hdmi", "sound_file", (int *)path, sizeof(path) / 4)) { db_warn("unknown sound file, use default\n"); strcpy(path, "/dragonboard/data/test48000.pcm"); } if (script_fetch("hdmi", "samplerate", &samplerate, 1)) { db_warn("unknown samplerate, use default #48000\n"); samplerate = 48000; } db_msg("samplerate #%d\n", samplerate); err = snd_pcm_open(&playback_handle, "hw:1,0", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { db_error("cannot open audio device (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_malloc(&hw_params); if (err < 0) { db_error("cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_any(playback_handle, hw_params); if (err < 0) { db_error("cannot initialize hardware parameter structure (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { db_error("cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16_LE); if (err < 0) { db_error("cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_set_rate(playback_handle, hw_params, samplerate, 0); if (err < 0) { db_error("cannot set sample rate (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2); if (err < 0) { db_error("cannot set channel count (%s), err = %d\n", snd_strerror(err), err); pthread_exit((void *)-1); } err = snd_pcm_hw_params(playback_handle, hw_params); if (err < 0) { db_error("cannot set parameters (%s)\n", snd_strerror(err)); pthread_exit((void *)-1); } snd_pcm_hw_params_free(hw_params); db_msg("open test pcm file: %s\n", path); fp = fopen(path, "r"); if (fp == NULL) { db_error("cannot open test pcm file(%s)\n", strerror(errno)); pthread_exit((void *)-1); } db_msg("play it...\n"); while (1) { while (!feof(fp)) { if (sound_play_stop) { goto out; } err = fread(buf, 1, BUF_LEN, fp); if (err < 0) { db_warn("read test pcm failed(%s)\n", strerror(errno)); } err = snd_pcm_writei(playback_handle, buf, BUF_LEN/4); if (err < 0) { err = xrun_recovery(playback_handle, err); if (err < 0) { db_warn("write error: %s\n", snd_strerror(err)); } } if (err == -EBADFD) { db_warn("PCM is not in the right state (SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING)\n"); } if (err == -EPIPE) { db_warn("an underrun occurred\n"); } if (err == -ESTRPIPE) { db_warn("a suspend event occurred (stream is suspended and waiting for an application recovery)\n"); } if (feof(fp)) { fseek(fp, 0L, SEEK_SET); } } } out: db_msg("play end...\n"); fclose(fp); snd_pcm_close(playback_handle); pthread_exit(0); }
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; }
static void async_direct_callback(snd_async_handler_t *ahandler) { snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); struct sniffer_state *sns = snd_async_handler_get_callback_private(ahandler); 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 = 0, err; while (1) { state = snd_pcm_state(handle); if (state == SND_PCM_STATE_XRUN) { err = xrun_recovery(handle, -EPIPE); if (err < 0) { printf("XRUN recovery failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } else if (state == SND_PCM_STATE_SUSPENDED) { err = xrun_recovery(handle, -ESTRPIPE); if (err < 0) { printf("SUSPEND recovery failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } } avail = snd_pcm_avail_update(handle); if (avail < 0) { err = xrun_recovery(handle, avail); if (err < 0) { printf("avail update failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; continue; } if (avail < sns->period_size) { if (first) { first = 0; err = snd_pcm_start(handle); if (err < 0) { printf("Start error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } } else { break; } continue; } size = sns->period_size; while (size > 0) { frames = size; err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames); if (err < 0) { if ((err = xrun_recovery(handle, err)) < 0) { printf("MMAP begin avail error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } printf("Callback %d %d\n", (int)offset, (int)frames); int i; for(i=0; i<frames; i++) *(__u8 *)(my_areas[0].addr + offset + i)=i%64; //generate_sine(my_areas, offset, frames, &sns->phase); commitres = snd_pcm_mmap_commit(handle, offset, frames); if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) { if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) { printf("MMAP commit error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } first = 1; } size -= frames; } } }
static gint gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length) { GstAlsaSink *alsa; gint err; gint cptr; guint8 *ptr = data; alsa = GST_ALSA_SINK (asink); if (alsa->iec958 && alsa->need_swap) { guint i; guint16 *ptr_tmp = (guint16 *) ptr; GST_DEBUG_OBJECT (asink, "swapping bytes"); for (i = 0; i < length / 2; i++) { ptr_tmp[i] = GUINT16_SWAP_LE_BE (ptr_tmp[i]); } } GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length); cptr = length / alsa->bpf; GST_ALSA_SINK_LOCK (asink); while (cptr > 0) { /* start by doing a blocking wait for free space. Set the timeout * to 4 times the period time */ err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000)); if (err < 0) { GST_DEBUG_OBJECT (asink, "wait error, %d", err); } else { GST_DELAY_SINK_LOCK (asink); err = snd_pcm_writei (alsa->handle, ptr, cptr); GST_DELAY_SINK_UNLOCK (asink); } GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr); if (err < 0) { GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err)); if (err == -EAGAIN) { continue; } else if (err == -ENODEV) { goto device_disappeared; } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { goto write_error; } continue; } ptr += snd_pcm_frames_to_bytes (alsa->handle, err); cptr -= err; } GST_ALSA_SINK_UNLOCK (asink); return length - (cptr * alsa->bpf); write_error: { GST_ALSA_SINK_UNLOCK (asink); return length; /* skip one period */ } device_disappeared: { GST_ELEMENT_ERROR (asink, RESOURCE, WRITE, (_("Error outputting to audio device. " "The device has been disconnected.")), (NULL)); goto write_error; } }
int main(int argc, char **argv) { char *outFile; char *inFile[1]; // FILE *fout; FILE *fin[1]; /*Holds the audio that will be written to file (16 bits per sample)*/ short out[FRAME_SIZE]; //int i; int result, length, tot_len; /*保存编码的状态*/ static void *stateDecode; /*保存字节因此他们可以被speex常规读写*/ static SpeexBits bitsDecode; //模式寄存器 static const SpeexMode *mode=NULL; //解码器的采样频率 static int speexFrequency = SAMPLERATE; //编码器的采样率 /*得到的缓冲区的大小*/ static spx_int32_t frame_size; /*得到的缓冲区的大小*/ //static int channe = CHANNELS; /*得到是立体声*/ //static SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; //单声到 立体声 /* 初始话IP端口结构*/ #if (SAMPLERATE == 8000) mode = speex_lib_get_mode (SPEEX_MODEID_NB); //宽带编码 #elif (SAMPLERATE == 16000) mode = speex_lib_get_mode (SPEEX_MODEID_WB); //宽带编码 #elif (SAMPLERATE == 32000) mode = speex_lib_get_mode (SPEEX_MODEID_UWB); //宽带编码 #endif //mode = speex_lib_get_mode (SPEEX_MODEID_UWB); //在宽带模式解码 stateDecode = speex_decoder_init(mode); //新建一个解码器 speex_encoder_ctl(stateDecode, SPEEX_GET_FRAME_SIZE, &frame_size); //得到缓冲区大小 speex_decoder_ctl(stateDecode, SPEEX_SET_SAMPLING_RATE, &speexFrequency); //设置解码器的采样频率 speex_bits_init(&bitsDecode); //初始解码器 char cbits[200]; int nbBytes; /*Holds the state of the decoder*/ //void *state; /*Holds bits so they can be read and written to by the Speex routines*/ //SpeexBits bits; int i, tmp; int rc; printf("%s: start\n", __func__); #if (SOUND_INTERFACE == SOUND_OSS) init_oss_play(); #elif (SOUND_INTERFACE == SOUND_ALSA) init_alsa_play(); #endif /*Create a new decoder state in narrowband mode*/ stateDecode = speex_decoder_init(&speex_uwb_mode); /*Set the perceptual enhancement on*/ tmp=1; speex_decoder_ctl(stateDecode, SPEEX_SET_ENH, &tmp); //printf("%s: 22222222\n", __func__); inFile[0] = argv[1]; //inFile[1] = argv[2]; // outFile = argv[1]; //fout = fopen(outFile, "w"); fin[0] = fopen(inFile[0], "r");//打开输入的spx文件 if(fin[0] ==NULL) { perror("打开文件错误"); exit(1); } //printf("%s: 3333333\n", __func__); /*Initialization of the structure that holds the bits*/ speex_bits_init(&bitsDecode); //printf("%s: 4444444\n", __func__); while (1) { //printf("%s: 55555\n", __func__); //printf("%s: 1111111\n", __func__); speex_bits_reset(&bitsDecode); /*Read the size encoded by sampleenc, this part will likely be different in your application*/ fread(&nbBytes, sizeof(int), 1, fin[0]); fprintf (stderr, "nbBytes: %d\n", nbBytes); if (feof(fin[0])) break; //printf("%s: 666\n", __func__); /*Read the "packet" encoded by sampleenc*/ fread(cbits, 1, nbBytes, fin[0]); /*Copy the data into the bit-stream struct*/ speex_bits_read_from(&bitsDecode, cbits, nbBytes); /*Decode the data*/ speex_decode_int(stateDecode, &bitsDecode, out); #if 0 /*Copy from float to short (16 bits) for output*/ for (i=0;i<FRAME_SIZE;i++) out[i]=output[i]; //printf("%s: 88888\n", __func__); /*Write the decoded audio to file*/ //fwrite(out, sizeof(short), FRAME_SIZE, fout); #endif #if (SOUND_INTERFACE == SOUND_OSS) rc = write(fdsoundplay, out, (SAMPLERATE/1000*READMSFORONCE)*sizeof(short)); if(rc != (SAMPLERATE/1000*READMSFORONCE)*sizeof(short)) { printf("写入数据长度与预期不符合\n"); } #elif (SOUND_INTERFACE == SOUND_ALSA) rc = snd_pcm_writei(handle, out, (SAMPLERATE/1000*READMSFORONCE)); //printf("%s: 99999\n", __func__); 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)); rc = xrun_recovery(handle, rc); if (rc < 0) { printf("Write error: %s\n", snd_strerror(rc)); //return -1; } } else if (rc != (int)(SAMPLERATE/1000*READMSFORONCE)) { fprintf(stderr, "short write, write %d frames\n", rc); } #endif } printf("end\n"); /*Destroy the decoder state*/ speex_decoder_destroy(stateDecode); /*Destroy the bit-stream truct*/ speex_bits_destroy(&bitsDecode); fclose(fin[0]); return 0; }
qint64 QAudioInputPrivate::read(char* data, qint64 len) { // Read in some audio data and write it to QIODevice, pull mode if ( !handle ) return 0; // bytesAvaiable is saved as a side effect of checkBytesReady(). int bytesToRead = checkBytesReady(); if (bytesToRead < 0) { // bytesAvailable as negative is error code, try to recover from it. xrun_recovery(bytesToRead); bytesToRead = checkBytesReady(); if (bytesToRead < 0) { // recovery failed must stop and set error. close(); errorState = QAudio::IOError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); return 0; } } bytesToRead = qMin<qint64>(len, bytesToRead); bytesToRead -= bytesToRead % period_size; int count=0, err = 0; while(count < 5) { int chunks = bytesToRead/period_size; int frames = chunks*period_frames; if(frames > (int)buffer_frames) frames = buffer_frames; int readFrames = snd_pcm_readi(handle, audioBuffer, frames); if (readFrames >= 0) { err = snd_pcm_frames_to_bytes(handle, readFrames); #ifdef DEBUG_AUDIO qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData(); #endif break; } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { errorState = QAudio::IOError; err = 0; break; } else { if(readFrames == -EPIPE) { errorState = QAudio::UnderrunError; err = snd_pcm_prepare(handle); } else if(readFrames == -ESTRPIPE) { err = snd_pcm_prepare(handle); } if(err != 0) break; } count++; } if(err > 0) { // got some send it onward #ifdef DEBUG_AUDIO qDebug()<<"frames to write to QIODevice = "<< snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes"; #endif if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return 0; if (pullMode) { qint64 l = audioSource->write(audioBuffer,err); if(l < 0) { close(); errorState = QAudio::IOError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); } else if(l == 0) { if (deviceState != QAudio::IdleState) { errorState = QAudio::NoError; deviceState = QAudio::IdleState; emit stateChanged(deviceState); } } else { bytesAvailable -= err; totalTimeValue += err; resuming = false; if (deviceState != QAudio::ActiveState) { errorState = QAudio::NoError; deviceState = QAudio::ActiveState; emit stateChanged(deviceState); } } return l; } else { memcpy(data,audioBuffer,err); bytesAvailable -= err; totalTimeValue += err; resuming = false; if (deviceState != QAudio::ActiveState) { errorState = QAudio::NoError; deviceState = QAudio::ActiveState; emit stateChanged(deviceState); } return err; } } return 0; }
/** * The process callback for this JACK application. * It is called by JACK at the appropriate times. */ int process (jack_nframes_t nframes, void *arg) { int rlen; int err; snd_pcm_sframes_t delay = target_delay; int i; delay = (num_periods*period_size)-snd_pcm_avail( alsa_handle ) ; delay -= jack_frames_since_cycle_start( client ); // Do it the hard way. // this is for compensating xruns etc... if( delay > (target_delay+max_diff) ) { snd_pcm_rewind( alsa_handle, delay - target_delay ); output_new_delay = (int) delay; delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. // first look at the PI controller, this code is just a special case, which should never execute once // everything is swung in. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } if( delay < (target_delay-max_diff) ) { output_new_delay = (int) delay; while ((target_delay-delay) > 0) { snd_pcm_uframes_t to_write = ((target_delay-delay) > 512) ? 512 : (target_delay-delay); snd_pcm_writei( alsa_handle, tmpbuf, to_write ); delay += to_write; } delay = target_delay; // Set the resample_rate... we need to adjust the offset integral, to do this. offset_integral = - (resample_mean - static_resample_factor) * catch_factor * catch_factor2; // Also clear the array. we are beginning a new control cycle. for( i=0; i<smooth_size; i++ ) offset_array[i] = 0.0; } /* ok... now we should have target_delay +- max_diff on the alsa side. * * calculate the number of frames, we want to get. */ double offset = delay - target_delay; // Save offset. offset_array[(offset_differential_index++)% smooth_size ] = offset; // Build the mean of the windowed offset array // basically fir lowpassing. double smooth_offset = 0.0; for( i=0; i<smooth_size; i++ ) smooth_offset += offset_array[ (i + offset_differential_index-1) % smooth_size] * window_array[i]; smooth_offset /= (double) smooth_size; // this is the integral of the smoothed_offset offset_integral += smooth_offset; // Clamp offset. // the smooth offset still contains unwanted noise // which would go straigth onto the resample coeff. // it only used in the P component and the I component is used for the fine tuning anyways. if( fabs( smooth_offset ) < pclamp ) smooth_offset = 0.0; // ok. now this is the PI controller. // u(t) = K * ( e(t) + 1/T \int e(t') dt' ) // K = 1/catch_factor and T = catch_factor2 double current_resample_factor = static_resample_factor - smooth_offset / (double) catch_factor - offset_integral / (double) catch_factor / (double)catch_factor2; // now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt. current_resample_factor = floor( (current_resample_factor - resample_mean) * controlquant + 0.5 ) / controlquant + resample_mean; // Output "instrumentatio" gonna change that to real instrumentation in a few. output_resampling_factor = (float) current_resample_factor; output_diff = (float) smooth_offset; output_integral = (float) offset_integral; output_offset = (float) offset; // Clamp a bit. if( current_resample_factor < resample_lower_limit ) current_resample_factor = resample_lower_limit; if( current_resample_factor > resample_upper_limit ) current_resample_factor = resample_upper_limit; // Now Calculate how many samples we need. rlen = ceil( ((double)nframes) * current_resample_factor )+2; assert( rlen > 2 ); // Calculate resample_mean so we can init ourselves to saner values. resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor; /* * now this should do it... */ outbuf = alloca( rlen * formats[format].sample_size * num_channels ); resampbuf = alloca( rlen * sizeof( float ) ); /* * render jack ports to the outbuf... */ int chn = 0; JSList *node = playback_ports; JSList *src_node = playback_srcs; SRC_DATA src; while ( node != NULL) { jack_port_t *port = (jack_port_t *) node->data; float *buf = jack_port_get_buffer (port, nframes); SRC_STATE *src_state = src_node->data; src.data_in = buf; src.input_frames = nframes; src.data_out = resampbuf; src.output_frames = rlen; src.end_of_input = 0; src.src_ratio = current_resample_factor; src_process( src_state, &src ); formats[format].jack_to_soundcard( outbuf + format[formats].sample_size * chn, resampbuf, src.output_frames_gen, num_channels*format[formats].sample_size, NULL); src_node = jack_slist_next (src_node); node = jack_slist_next (node); chn++; } // now write the output... again: err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); //err = snd_pcm_writei(alsa_handle, outbuf, src.output_frames_gen); if( err < 0 ) { printf( "err = %d\n", err ); if (xrun_recovery(alsa_handle, err) < 0) { printf("Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } goto again; } return 0; }
int alsamm_send_dacs(void) { static double timenow,timelast; t_sample *fpo, *fpi, *fp1, *fp2; int i, err, devno; const snd_pcm_channel_area_t *my_areas; snd_pcm_sframes_t size; snd_pcm_sframes_t commitres; snd_pcm_state_t state; snd_pcm_sframes_t ooffset, oavail; snd_pcm_sframes_t ioffset, iavail; /* unused channels should be zeroed out on startup (open) and stay this */ int inchannels = STUFF->st_inchannels; int outchannels = STUFF->st_outchannels; timelast = sys_getrealtime(); #ifdef ALSAMM_DEBUG if(dac_send++ < 0) post("dac send called in %d, out %d, xrun %d",inchannels,outchannels, alsamm_xruns); if(alsamm_xruns && (alsamm_xruns % 1000) == 0) post("1000 xruns accoured"); if(dac_send < WATCH_PERIODS){ out_cm[dac_send] = -1; in_avail[dac_send] = out_avail[dac_send] = -1; in_offset[dac_send] = out_offset[dac_send] = -1; outaddr[dac_send] = inaddr[dac_send] = NULL; xruns_watch[dac_send] = alsamm_xruns; } #endif if (!inchannels && !outchannels) { return SENDDACS_NO; } /* here we should check if in and out samples are here. but, the point is if out samples available also in sample should, so we don't make a precheck of insamples here and let outsample check be the the first of the forst card. */ /* OUTPUT Transfer */ fpo = STUFF->st_soundout; for(devno = 0;devno < alsa_noutdev;devno++){ t_alsa_dev *dev = &alsa_outdev[devno]; snd_pcm_t *out = dev->a_handle; int ochannels =dev->a_channels; /* how much samples available ??? */ oavail = snd_pcm_avail_update(out); /* only one reason i can think about, the driver stopped and says broken pipe so this should not happen if we have enough stopthreshhold but if try to restart with next commit */ if (oavail < 0) { #ifdef ALSAMM_DEBUG broken_opipe++; #endif err = xrun_recovery(out, -EPIPE); if (err < 0) { check_error(err,"otavail<0 recovery failed"); return SENDDACS_NO; } oavail = snd_pcm_avail_update(out); } /* check if we are late and have to (able to) catch up */ /* xruns will be ignored since you cant do anything since already happened */ state = snd_pcm_state(out); if (state == SND_PCM_STATE_XRUN) { err = xrun_recovery(out, -EPIPE); if (err < 0) { check_error(err,"DAC XRUN recovery failed"); return SENDDACS_NO; } oavail = snd_pcm_avail_update(out); } else if (state == SND_PCM_STATE_SUSPENDED) { err = xrun_recovery(out, -ESTRPIPE); if (err < 0) { check_error(err,"DAC SUSPEND recovery failed"); return SENDDACS_NO; } oavail = snd_pcm_avail_update(out); } #ifdef ALSAMM_DEBUG if(dac_send < WATCH_PERIODS){ out_avail[dac_send] = oavail; } #endif /* we only transfer transfersize of bytes request, this should only happen on first card otherwise we got a problem :-(()*/ if(oavail < alsamm_transfersize){ return SENDDACS_NO; } /* transfer now */ size = alsamm_transfersize; fp1 = fpo; ooffset = 0; /* since this can go over a buffer boundery we maybe need two steps to transfer (normally when buffersize is a multiple of transfersize this should never happen) */ while (size > 0) { int chn; snd_pcm_sframes_t oframes; oframes = size; err = alsamm_get_channels(out, (unsigned long *)&oframes, (unsigned long *)&ooffset,ochannels,dev->a_addr); #ifdef ALSAMM_DEBUG if(dac_send < WATCH_PERIODS){ out_offset[dac_send] = ooffset; outaddr[dac_send] = (char *) dev->a_addr[0]; } #endif if (err < 0){ if ((err = xrun_recovery(out, err)) < 0) { check_error(err,"MMAP begins avail error"); break; /* next card please */ } } /* transfer into memory */ for (chn = 0; chn < ochannels; chn++) { t_alsa_sample32 *buf = (t_alsa_sample32 *)dev->a_addr[chn]; /* osc(buf, oframes, (dac_send%1000 < 500)?-100.0:-10.0,440,&(indexes[chn])); */ for (i = 0, fp2 = fp1 + chn*alsamm_transfersize; i < oframes; i++,fp2++) { float s1 = *fp2 * F32MAX; /* better but slower, better never clip ;-) buf[i]= CLIP32(s1); */ buf[i]= ((int) s1 & 0xFFFFFF00); *fp2 = 0.0; } } commitres = snd_pcm_mmap_commit(out, ooffset, oframes); if (commitres < 0 || commitres != oframes) { if ((err = xrun_recovery(out, commitres >= 0 ? -EPIPE : commitres)) < 0) { check_error(err,"MMAP commit error"); return SENDDACS_NO; } } #ifdef ALSAMM_DEBUG if(dac_send < WATCH_PERIODS) out_cm[dac_send] = oframes; #endif fp1 += oframes; size -= oframes; } /* while size */ fpo += ochannels*alsamm_transfersize; }/* for devno */ fpi = STUFF->st_soundin; /* star first card first channel */ for(devno = 0;devno < alsa_nindev;devno++){ t_alsa_dev *dev = &alsa_indev[devno]; snd_pcm_t *in = dev->a_handle; int ichannels = dev->a_channels; iavail = snd_pcm_avail_update(in); if (iavail < 0) { err = xrun_recovery(in, iavail); if (err < 0) { check_error(err,"input avail update failed"); return SENDDACS_NO; } iavail=snd_pcm_avail_update(in); } state = snd_pcm_state(in); if (state == SND_PCM_STATE_XRUN) { err = xrun_recovery(in, -EPIPE); if (err < 0) { check_error(err,"ADC XRUN recovery failed"); return SENDDACS_NO; } iavail=snd_pcm_avail_update(in); } else if (state == SND_PCM_STATE_SUSPENDED) { err = xrun_recovery(in, -ESTRPIPE); if (err < 0) { check_error(err,"ADC SUSPEND recovery failed"); return SENDDACS_NO; } iavail=snd_pcm_avail_update(in); } /* only transfer full transfersize or nothing */ if(iavail < alsamm_transfersize){ return SENDDACS_NO; } size = alsamm_transfersize; fp1 = fpi; ioffset = 0; /* since sysdata can go over a driver buffer boundery we maybe need two steps to transfer (normally when buffersize is a multiple of transfersize this should never happen) */ while(size > 0){ int chn; snd_pcm_sframes_t iframes = size; err = alsamm_get_channels(in, (unsigned long *)&iframes, (unsigned long *)&ioffset,ichannels,dev->a_addr); if (err < 0){ if ((err = xrun_recovery(in, err)) < 0) { check_error(err,"MMAP begins avail error"); return SENDDACS_NO; } } #ifdef ALSAMM_DEBUG if(dac_send < WATCH_PERIODS){ in_avail[dac_send] = iavail; in_offset[dac_send] = ioffset; inaddr[dac_send] = dev->a_addr[0]; } #endif /* transfer into memory */ for (chn = 0; chn < ichannels; chn++) { t_alsa_sample32 *buf = (t_alsa_sample32 *) dev->a_addr[chn]; for (i = 0, fp2 = fp1 + chn*alsamm_transfersize; i < iframes; i++,fp2++) { /* mask the lowest bits, since subchannels info can make zero samples nonzero */ *fp2 = (float) ((t_alsa_sample32) (buf[i] & 0xFFFFFF00)) * (1.0 / (float) INT32_MAX); } } commitres = snd_pcm_mmap_commit(in, ioffset, iframes); if (commitres < 0 || commitres != iframes) { post("please never"); if ((err = xrun_recovery(in, commitres >= 0 ? -EPIPE : commitres)) < 0) { check_error(err,"MMAP synced in commit error"); return SENDDACS_NO; } } fp1 += iframes; size -= iframes; } fpi += ichannels*alsamm_transfersize; } /* for out devno < alsamm_outcards*/ if ((timenow = sys_getrealtime()) > (timelast + sleep_time)) { #ifdef ALSAMM_DEBUG if(dac_send < 10 && sys_verbose) post("slept %f > %f + %f (=%f)", timenow,timelast,sleep_time,(timelast + sleep_time)); #endif return (SENDDACS_SLEPT); } return SENDDACS_YES; }
qint64 QAlsaAudioInput::read(char* data, qint64 len) { // Read in some audio data and write it to QIODevice, pull mode if ( !handle ) return 0; int bytesRead = 0; int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer(); if (ringBuffer.bytesOfDataInBuffer() < len) { // bytesAvaiable is saved as a side effect of checkBytesReady(). int bytesToRead = checkBytesReady(); if (bytesToRead < 0) { // bytesAvailable as negative is error code, try to recover from it. xrun_recovery(bytesToRead); bytesToRead = checkBytesReady(); if (bytesToRead < 0) { // recovery failed must stop and set error. close(); errorState = QAudio::IOError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); return 0; } } bytesToRead = qMin<qint64>(len, bytesToRead); bytesToRead = qMin<qint64>(ringBuffer.freeBytes(), bytesToRead); bytesToRead -= bytesToRead % period_size; int count=0; int err = 0; while(count < 5 && bytesToRead > 0) { char buffer[bytesToRead]; int chunks = bytesToRead / period_size; int frames = chunks * period_frames; if (frames > (int)buffer_frames) frames = buffer_frames; int readFrames = snd_pcm_readi(handle, buffer, frames); bytesRead = snd_pcm_frames_to_bytes(handle, readFrames); if (m_volume < 1.0f) QAudioHelperInternal::qMultiplySamples(m_volume, settings, buffer, buffer, bytesRead); if (readFrames >= 0) { ringBuffer.write(buffer, bytesRead); #ifdef DEBUG_AUDIO qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData(); #endif break; } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { errorState = QAudio::IOError; err = 0; break; } else { if(readFrames == -EPIPE) { errorState = QAudio::UnderrunError; err = snd_pcm_prepare(handle); } else if(readFrames == -ESTRPIPE) { err = snd_pcm_prepare(handle); } if(err != 0) break; } count++; } } bytesRead += bytesInRingbufferBeforeRead; if (bytesRead > 0) { // got some send it onward #ifdef DEBUG_AUDIO qDebug() << "frames to write to QIODevice = " << snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes"; #endif if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return 0; if (pullMode) { qint64 l = 0; qint64 bytesWritten = 0; while (ringBuffer.bytesOfDataInBuffer() > 0) { l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize()); if (l > 0) { ringBuffer.readBytes(l); bytesWritten += l; } else { break; } } if (l < 0) { close(); errorState = QAudio::IOError; deviceState = QAudio::StoppedState; emit stateChanged(deviceState); } else if (l == 0 && bytesWritten == 0) { if (deviceState != QAudio::IdleState) { errorState = QAudio::NoError; deviceState = QAudio::IdleState; emit stateChanged(deviceState); } } else { bytesAvailable -= bytesWritten; totalTimeValue += bytesWritten; resuming = false; if (deviceState != QAudio::ActiveState) { errorState = QAudio::NoError; deviceState = QAudio::ActiveState; emit stateChanged(deviceState); } } return bytesWritten; } else { while (ringBuffer.bytesOfDataInBuffer() > 0) { int size = ringBuffer.availableDataBlockSize(); memcpy(data, ringBuffer.availableData(), size); data += size; ringBuffer.readBytes(size); } bytesAvailable -= bytesRead; totalTimeValue += bytesRead; resuming = false; if (deviceState != QAudio::ActiveState) { errorState = QAudio::NoError; deviceState = QAudio::ActiveState; emit stateChanged(deviceState); } return bytesRead; } } return 0; }