/* * Audio Library for Linux and Windows * =================================== * Author: DJ0ABR * * Author: Kurt Moraw, Ham radio: DJ0ABR, github: dj0abr * License: GPL-3 * * compilation: * Windows ... Visual Studio * Linux ... make * * Documentation see: libkmaudio.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * libkmaudio_playback.cpp ... * starts a portaudio playback stream and a callback routine. Plays the * audio samples coming via the fifo (Windows only) */ #include "libkmaudio.h" #define FRAMES_PER_BUFFER 512 int playCallback(const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData); void close_playback_stream(int idx) { if (devlist[idx].pbStream != NULL) { Pa_CloseStream(devlist[idx].pbStream); devlist[idx].pbStream = NULL; } } int kmaudio_startPlayback(char* devname, int samprate) { printf("Start request for PB stream:%s\n", devname); if (devname == NULL || strlen(devname) < 3) // no devices defined yet { printf("no PB devices specified\n"); return -1; } int idx = searchDevice(devname, 1); if (idx == -1) { printf("Playback Device:<%s> not found\n", devname); return -1; } devlist[idx].working = 0; close_playback_stream(idx); printf("Starting PB stream:%s [%d]\n", devname, idx); io_fifo_clear(idx); devlist[idx].requested_samprate = samprate; if (getRealSamprate(idx) == -1) { printf("Samplerate %d not supported by device:<%s>\n", samprate, devname); return -1; } if (devlist[idx].requested_samprate != devlist[idx].real_samprate) resampler_create(idx); struct PaWasapiStreamInfo wasapiInfo; memset(&wasapiInfo, 0, sizeof(PaWasapiStreamInfo)); wasapiInfo.size = sizeof(PaWasapiStreamInfo); wasapiInfo.hostApiType = paWASAPI; wasapiInfo.version = 1; wasapiInfo.flags = (paWinWasapiExclusive | paWinWasapiThreadPriority); wasapiInfo.threadPriority = eThreadPriorityProAudio; devlist[idx].outputParameters.hostApiSpecificStreamInfo = (&wasapiInfo); PaError e = Pa_IsFormatSupported(&devlist[idx].outputParameters, NULL, (double)devlist[idx].real_samprate); printf("Playback : err:%d device:%d PAdev:%d samprate: %f chans:%d\n", e, idx, devlist[idx].devnum, (double)devlist[idx].real_samprate, devlist[idx].outputParameters.channelCount); devlist[idx].index = idx; int err = Pa_OpenStream( &devlist[idx].pbStream, NULL, &devlist[idx].outputParameters, (double)devlist[idx].real_samprate, FRAMES_PER_BUFFER, paClipOff, playCallback, &(devlist[idx].index)); if (err != paNoError) { printf("cannot open playback stream for device:<%s> %d\n", devname, err); return -1; } err = Pa_StartStream(devlist[idx].pbStream); if (err != paNoError) { printf("cannot start playback stream for device:<%s>\n", devname); return -1; } printf("Playback started sucessfully\n"); devlist[idx].working = 1; return idx; } int playCallback( const void* inputBuffer, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData) { int16_t* rptr = (int16_t*)outputBuffer; int devidx = *((int*)userData); int chans = devlist[devidx].outputParameters.channelCount; //measure_speed_bps(framesPerBuffer); int16_t f[FRAMES_PER_BUFFER]; memset(f, 0, sizeof(int16_t) * FRAMES_PER_BUFFER); unsigned int num = io_read_fifo_num_short(devidx, f, framesPerBuffer); if (num < framesPerBuffer) { //printf("got %d from fifo, requested %d\n", num, framesPerBuffer); } int av = io_fifo_elems_avail(devidx); for (unsigned int i = 0; i < framesPerBuffer; i++) { if (chans == 1) rptr[i] = f[i]; else { rptr[i * 2] = f[i]; rptr[i * 2 + 1] = f[i]; } } // Prevent unused variable warnings (void)inputBuffer; (void)timeInfo; (void)statusFlags; if (keeprunning == 1) return paContinue; return paComplete; }