static snd_pcm_sframes_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) { snd_pcm_file_t *file = pcm->private_data; snd_pcm_channel_area_t areas[pcm->channels]; snd_pcm_sframes_t n = snd_pcm_writen(file->gen.slave, bufs, size); if (n > 0) { snd_pcm_areas_from_bufs(pcm, areas, bufs); snd_pcm_file_add_frames(pcm, areas, 0, n); } return n; }
int SoundThread::playback_callback (snd_pcm_sframes_t nframes) { int err; //printf ("playback callback called with %d frames\n", (int)nframes); void *channelsbuffer[1]; channelsbuffer[0] = &samplebuffer; sndFIFO->read(samplebuffer, nframes); if ((err = snd_pcm_writen(playback_handle, (void **)channelsbuffer, nframes)) < 0) { fprintf (stderr, "write failed (%s)\n", snd_strerror (err)); } return err; }
TErrors SalsaStream::write(llaAudioPipe& buffer) { if(pcm_state_ == CLOSED) { LOGGER().warning(E_WRITE_STREAM, "Attempt to write to a closed stream."); return E_WRITE_STREAM; } TErrors err; if( (err = updateSettings(buffer)) != E_OK) return err; buffer.onSamplesReady(); if(buffer.fail()) { return E_WRITE_STREAM; } char *iraw, **niraw; int rc; getRawOutputBuffers(buffer, &iraw, &niraw); TSize frames_to_deliver = getBufferLastWrite(buffer); if( frames_to_deliver <= 0 || frames_to_deliver > buffer_size_) frames_to_deliver = buffer.getBufferLength(); if(organization_ == SND_PCM_ACCESS_RW_NONINTERLEAVED) { rc = snd_pcm_writen(pcm_, (void**)niraw, frames_to_deliver); } else { rc = snd_pcm_writei(pcm_, (void*)iraw, frames_to_deliver); } if (rc == -EPIPE) { /* EPIPE means underrun */ snd_pcm_prepare(pcm_); } else if (rc < 0) { LOGGER().warning(E_WRITE_STREAM, snd_strerror(rc)); snd_pcm_recover(pcm_, rc, 0); return E_WRITE_STREAM; } return E_OK; }
//============================================================================== bool writeToOutputDevice (AudioBuffer<float>& outputChannelBuffer, const int numSamples) { jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels()); float* const* const data = outputChannelBuffer.getArrayOfWritePointers(); snd_pcm_sframes_t numDone = 0; if (isInterleaved) { scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false); for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples); numDone = snd_pcm_writei (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples); } else { for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (data[i], data[i], numSamples); numDone = snd_pcm_writen (handle, (void**) data, (snd_pcm_uframes_t) numSamples); } if (numDone < 0) { if (numDone == -(EPIPE)) underrunCount++; if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) numDone, 1 /* silent */))) return false; } if (numDone < numSamples) JUCE_ALSA_LOG ("Did not write all samples: numDone: " << numDone << ", numSamples: " << numSamples); return true; }
//============================================================================== bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples) { jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels()); float** const data = outputChannelBuffer.getArrayOfChannels(); snd_pcm_sframes_t numDone = 0; if (isInterleaved) { scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false); for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples); numDone = snd_pcm_writei (handle, scratch.getData(), numSamples); } else { for (int i = 0; i < numChannelsRunning; ++i) converter->convertSamples (data[i], data[i], numSamples); numDone = snd_pcm_writen (handle, (void**) data, numSamples); } if (failed (numDone)) { if (numDone == -EPIPE) { if (failed (snd_pcm_prepare (handle))) return false; } else if (numDone != -ESTRPIPE) return false; } return true; }
snd_pcm_sframes_t snd_pcm_generic_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) { snd_pcm_generic_t *generic = pcm->private_data; return snd_pcm_writen(generic->slave, bufs, size); }
int alsa_play_play(alsa_play_t alsa_play, glc_audio_data_header_t *audio_hdr, char *data) { snd_pcm_uframes_t frames, rem; snd_pcm_sframes_t ret = 0; unsigned int c; if (audio_hdr->id != alsa_play->id) return 0; if (!alsa_play->pcm) { glc_log(alsa_play->glc, GLC_ERROR, "alsa_play", "broken stream %d", alsa_play->id); return EINVAL; } frames = snd_pcm_bytes_to_frames(alsa_play->pcm, audio_hdr->size); glc_utime_t time = glc_state_time(alsa_play->glc); glc_utime_t duration = ((glc_utime_t) 1000000000 * (glc_utime_t) frames) / (glc_utime_t) alsa_play->rate; if (time + alsa_play->silence_threshold + duration < audio_hdr->time) { struct timespec ts = { .tv_sec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)/1000000000, .tv_nsec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)%1000000000 }; nanosleep(&ts,NULL); } /* * This condition determine what will be the initial audio packet. * it is preferable to be ahead by < duration/2 than behind * the video by > duration/2 */ else if (time > audio_hdr->time + duration/2) { glc_log(alsa_play->glc, GLC_DEBUG, "alsa_play", "dropped packet. now %" PRId64 " ts %" PRId64, time, audio_hdr->time); return 0; } rem = frames; while (rem > 0) { /* alsa is horrible... */ /*snd_pcm_wait(alsa_play->pcm, duration);*/ if (alsa_play->flags & GLC_AUDIO_INTERLEAVED) ret = snd_pcm_writei(alsa_play->pcm, &data[snd_pcm_frames_to_bytes(alsa_play->pcm, frames - rem)], rem); else { for (c = 0; c < alsa_play->channels; c++) alsa_play->bufs[c] = &data[snd_pcm_samples_to_bytes(alsa_play->pcm, frames) * c + snd_pcm_samples_to_bytes(alsa_play->pcm, frames - rem)]; ret = snd_pcm_writen(alsa_play->pcm, alsa_play->bufs, rem); } if (ret == 0) break; if ((ret == -EBUSY) || (ret == -EAGAIN)) break; else if (ret < 0) { if ((ret = alsa_play_xrun(alsa_play, ret))) { glc_log(alsa_play->glc, GLC_ERROR, "alsa_play", "xrun recovery failed: %s", snd_strerror(-ret)); return ret; } } else rem -= ret; } return 0; }
int main(void) { /* Handle for the PCM device */ snd_pcm_t *pcm_handle = NULL; /* Playback stream */ snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; /* This structure contains information about * the hardware and can be used to specify the * configuration to be used for the PCM stream. */ snd_pcm_hw_params_t *hwparams; /* Name of the PCM device, like plughw:0,0 * The first number is the number of the soundcard, * the second number is the number ot the device. */ char * pcm_name; /* Init pcm_name. Of course, later you * will make this configurable; */ pcm_name = strdup("plughw:0,0"); /* Allocate the snd_pcm_hw_params_t structure on the stack.*/ snd_pcm_hw_params_alloca(&hwparams); /* Open PCM. the last parameter of this function is the mode. * If this is set to 0, the standard mode is used. Possible * other values are SND_PCM_NONBLOCK AND SND_PCM_ASYNC. * if SND_PCM_NONBLOCK is used, read/write access to the * PCM device will return immediately. If SND_PCM_ASYNC is * specified. SIGIO will be emitted whenever a period has * been completely processed by the soundcard. */ if(snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0){ fprintf(stderr, "Error opening PCM device %s\n", pcm_name); return (-1); } /* Init hwparams with full configuration space */ if(snd_pcm_hw_params_any(pcm_handle, hwparams) < 0){ fprintf(stderr, "Can not configure this PCM device.\n"); return (-1); } int rate = 44100; /* Sample rate */ int exact_rate; /* Sample rate returned by snd_pcm_hw_params_set_rate_near */ int dir; /* exact_rate == rate --> dir = 0 */ /* exact_rate < rate --> dir = -1 */ /* exact_rate > rate --> dir = 1 */ int periods = 2; /* Number of periods */ snd_pcm_uframes_t periodsize = 8192; /* Periodsize (bytes) */ /* Set access type. This can be either * SND_PCM_ACCESS_RW_INTERLEAVED or * SND_PCM_ACCESS_MMAP_NONINTERLEAVED. * There are also access types for MMAPed * access, but this is beyond the scope * of this introduction. */ if(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0){ fprintf(stderr, "Error setting access.\n"); return (-1); } /* Set sample format */ if(snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0){ fprintf(stderr, "Error setting format.\n"); return (-1); } /* Set sample rate. If the exact rate is not supported by the hardware, use nearest possbile rate. */ exact_rate = rate; if(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0){ fprintf(stderr, "Error setting rate.\n"); return (-1); } if(rate != exact_rate){ fprintf(stderr, "The rate %d HZ is not supported by your hardware.\n ==> Using %d HZ instead.\n", rate, exact_rate); } /* Set number of channels */ if(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0){ fprintf(stderr, "Error setting channels. \n"); return (-1); } /* Set number of periods. Periods used to be called fragments. */ if(snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0){ fprintf(stderr, "Error setting periods.\n"); return (-1); } /* Set buffer size (in frames). The resulting latency is given by * latency = periodsize * periods / (rate * bytes_per_frame) */ if(snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods) >> 2) < 0){ fprintf(stderr, "Error setting buffersize.\n"); return (-1); } /* Apply HW parameter settins to * PCM device and prepare device */ if(snd_pcm_hw_params(pcm_handle, hwparams) < 0){ fprintf(stderr, "Error setting HW params. \n"); return (-1); } #if 0 /* Write num_frames frames from buffer data to * the PCM device pointed to by pcm_handle. * Returns the number of frames actually written. */ snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, num_frames); #endif #if 0 /*Write num_frames frames from buffer data to * the PCM device pointed to by pcm_handle. * Returns the number of frames actually written. */ snd_pcm_sframes_t snd_pcm_writen(pcm_handle, data, num_frames); #endif unsigned char *data; int pcmreturn, l1, l2; short s1, s2; int frames; int num_frames = 1024; data = (unsigned char *)malloc(periodsize); frames = periodsize >> 2; for(l1 = 0; l1 < 100; l1++){ for(l2 = 0; l2 < num_frames; l2++){ s1 = (l2 % 128) * 100 - 5000; s2 = (l2 % 256) * 100 - 5000; data[4*l2] = (unsigned char)s1; data[4*l2+1] = s1 >> 8; data[4*l2+2] = (unsigned char)s2; data[4*l2+3] = s2 >> 8; } while((pcmreturn = snd_pcm_writei(pcm_handle, data, frames)) < 0){ snd_pcm_prepare(pcm_handle); fprintf(stderr, "<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>"); } } /* Stop PCM device and drop pending frames */ snd_pcm_drop(pcm_handle); /* Stop PCM device after pending frames have been played */ snd_pcm_drain(pcm_handle); return 0; }
int playback_file(unsigned rate, uint16_t channels, int fd, uint32_t total_count) { int rc; int size; uint32_t left_size; snd_pcm_t *handle; snd_pcm_hw_params_t *params; #ifdef INTEL int dir; #endif snd_pcm_uframes_t frames; char *buffer; /* TODO */ /* Allocate a hardware parameters object. */ rc = snd_pcm_hw_params_malloc(¶ms); if (rc < 0) { fprintf(stderr, "snd_pcm_hw_params_malloc: %s\n", snd_strerror(rc)); exit(1); } /* Open PCM device for playbacking. */ rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); //rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0); if (rc < 0) { fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc)); exit(1); } /* Fill it in with default values. */ rc = snd_pcm_hw_params_any(handle, params); if (rc < 0) { fprintf(stderr, "snd_pcm_hw_params_any: %s\n", snd_strerror(rc)); return 1; } /* Set the desired hardware parameters. */ /* Interleaved mode */ #ifdef INTERLEAVED rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); #else rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED); #endif if (rc < 0) { fprintf(stderr, "snd_pcm_hw_params_set_access: %d %s\n", rc, snd_strerror(rc)); //return 1; } /* Signed 16-bit little-endian format */ snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* Two channels (stereo) */ snd_pcm_hw_params_set_channels(handle, params, channels); /* 44100 bits/second sampling rate (CD quality) */ #ifdef INTEL snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir); #else snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0); #endif /* Set period size to 32 frames. */ frames = 32; #ifdef INTEL snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); #else snd_pcm_hw_params_set_period_size_near(handle, params, &frames, 0); #endif /* Write the parameters to the driver */ rc = snd_pcm_hw_params(handle, params); if (rc < 0) { fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc)); exit(1); } /* Use a buffer large enough to hold one period */ #ifdef INTEL snd_pcm_hw_params_get_period_size(params, &frames, &dir); #else snd_pcm_hw_params_get_period_size(params, &frames, 0); #endif fprintf(stderr, "get period size: %d\n", frames); size = frames * 16 / 8 * channels; /* 2 bytes/sample(16bit), 2 channels */ buffer = (char *) malloc(size); // while (left_size > 0) { while (1) { rc = read(fd, buffer, size); if(rc <= 0) { printf("at the end of file, exiting...\n"); break; } totle_size += rc; /* totle data size */ left_size = total_count - totle_size; if (rc != size) fprintf(stderr, "short read: read %d bytes\n", rc); #ifdef INTERLEAVED rc = snd_pcm_writei(handle, buffer, frames); #else void* Data[2]; Data[0] = (void*)buffer; Data[1] = (void*)buffer; rc = snd_pcm_writen(handle, Data, frames); #endif if (rc == -EPIPE) { /* EPIPE means overrun */ fprintf(stderr, "overrun occurred\n"); snd_pcm_prepare(handle); } else if (rc < 0) { fprintf(stderr, "error from write: %s\n", snd_strerror(rc)); } else if (rc != (int)frames) { fprintf(stderr, "short write, write %d frames\n", rc); } if(left_size <= 0){ lseek(fd, sizeof(hdr), SEEK_SET); totle_size = 0; printf("again \n"); // read(fd, &hdr, sizeof(hdr)); } } fprintf(stderr, "closing device \n"); snd_pcm_drop(handle); fprintf(stderr, "4 \n"); snd_pcm_drain(handle); fprintf(stderr, "3 \n"); snd_pcm_close(handle); fprintf(stderr, "2 \n"); if(params) { snd_pcm_hw_params_free(params); } fprintf(stderr, "1 \n"); free(buffer); fprintf(stderr, "exit \n"); return 0; }