⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dspoutalsa.cpp

📁 KphoneSI (kpsi) is a SIP (Session Initiation Protocol) user agent for Linux, with which you can in
💻 CPP
字号:
#include <stdio.h>#include <time.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#define ALSA_PCM_NEW_HW_PARAMS_API//#define ALSADEBUG#include "dspoutalsa.h"static snd_pcm_uframes_t chunk_size = 0;static snd_pcm_uframes_t period_frames = 0;DspOutAlsa::DspOutAlsa( const QString &devName )	: DspOut(){	devname = devName;	setDeviceName( "alsa" );	rate = 8000;}DspOutAlsa::~DspOutAlsa( void ){	if(devstate == DeviceOpened) {		snd_pcm_drain( handle);		snd_pcm_close( handle);	}}bool DspOutAlsa::openDevice( DeviceMode mode ){	unsigned int exact_rate;	int dir;	// set nonblock and leave, if device blocked	if( mode == ReadOnly ) {		if ((err = snd_pcm_open( &handle, devname, SND_PCM_STREAM_CAPTURE,1)) < 0) { 			printf ( "cannot open audio device (%s)\n", snd_strerror (err));			return false;		}	} else {		if ((err = snd_pcm_open( &handle, devname, SND_PCM_STREAM_PLAYBACK, 1)) < 0) { 			printf ( "cannot open audio device (%s)\n",  snd_strerror (err));			return false;		}	} // set blocking mode	snd_pcm_nonblock(handle,0);		snd_pcm_hw_params_alloca( &hw_params);		if ((err = snd_pcm_hw_params_any( handle, hw_params)) < 0) {		printf ( "cannot initialize hardware parameter structure (%s)\n",			 snd_strerror (err));		exit (1);	}	if ((err = snd_pcm_hw_params_set_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {		printf ( "cannot set access type (%s)\n",			 snd_strerror (err));		exit (1);	}	if ((err = snd_pcm_hw_params_set_format( handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {		printf ( "cannot set sample format (%s)\n",			 snd_strerror (err));		exit (1);	}	if ((err = snd_pcm_hw_params_set_channels( handle, hw_params, 2 )) < 0) {		printf ( "cannot set channel count (%s)\n",			 snd_strerror (err));		exit (1);	}	exact_rate = rate;	dir = 0;	if ((err = snd_pcm_hw_params_set_rate_near( handle, hw_params, &exact_rate, &dir )) < 0) {		printf ( "cannot set rate (%s)\n",			 snd_strerror (err));		exit (1);	}	if (dir != 0) {		printf( "The rate %d Hz is not supported by your hardware.\n==> Using %d Hz instead.\n", rate, exact_rate);	}	period_frames = 32; 	if ((err = snd_pcm_hw_params_set_period_size_near( handle, hw_params, &period_frames, &dir)) < 0) {		printf ( "cannot set sample format (%s)\n",			 snd_strerror (err));		exit (1);	}		if ((err = snd_pcm_hw_params( handle, hw_params )) < 0) {		printf ( "cannot set parameters (%s)\n",			 snd_strerror (err));		exit (1);	}	snd_pcm_hw_params_get_period_size( hw_params, &chunk_size, &dir );	snd_pcm_hw_params_get_buffer_size( hw_params, &buffer_size );	audio_buf.resize( chunk_size*2 );	if (chunk_size == buffer_size) {		printf ( "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size);		exit (1);	}	lasterror = QString::null;	devstate = DeviceOpened;  	return true;}bool DspOutAlsa::writeBuffer( void ){	snd_pcm_sframes_t delay;	struct timespec waitTime;	waitTime.tv_sec = 0;	waitTime.tv_nsec = 100000;			if( devstate != DeviceOpened ) {		lasterror = "Device Not Open";		return false;	}	int rc;	size_t count = audio_buf.getSize();	void *buf;	int8_t x0 = 0;	int8_t x1 = 0;	buf = alloca(2*(count+20));	int8_t *b1 = reinterpret_cast<int8_t*>(audio_buf.getData());	int8_t *b2 = reinterpret_cast<int8_t*>(buf);	for( size_t i=0; i < count/2; i++ ) {		x0 = b1[2*i];		x1 = b1[2*i+1];		b2[4*i]   = x0;		b2[4*i+1] = x1;		b2[4*i+2] = x0;		b2[4*i+3] = x1;	}		if (snd_pcm_delay(handle, &delay) < 0) { //FIXME: maybe this should go to another location#ifdef ALSADEBUG		printf( "w:snd_pcm_delay failed\n");#endif		// this probably means a buffer underrund, therefore delay = 0 		delay = 0; //FIXME: check for buffer underrun	}		if (delay > (int)rate/10) { // more than 0.1 s delay #ifdef ALSADEBUG		printf("w:too high delay: %d, dropping data\n", delay);#endif		return true;	} else if ((delay + count/2) < (rate/200)) { // after writing samples less than 5 ms delay #ifdef ALSADEBUG		printf("w:too little delay: %d,%d, underrun likely, inserting additional samples\n", delay+count/2,rate/200);#endif		for( size_t i = count/2; i < count/2 + 10; i++ ) {			b2[4*i]   = x0;			b2[4*i+1] = x1;			b2[4*i+2] = x0;			b2[4*i+3] = x1;		}		count += 20;	}	int8_t *buff = (int8_t*) buf;	while ((rc = snd_pcm_writei(handle, buff, count/2)) != (int)count/2) {		if (rc >= 0) {			/* This should never happen, because we opened the device in blocking mode */#ifdef ALSADEBUG			printf(  "w:write %d instead of %d frames !\n", rc, (int)count/2);#endif			buff += rc*4;			count -= rc*2;			continue;		}		if (rc == -EPIPE) {			/* buffer underrun */#ifdef ALSADEBUG			printf( "w:buffer underrun\n");#endif			if (snd_pcm_prepare(handle) < 0) {				printf( "snd_pcm_prepare failed\n");			}			continue;		} else if (rc == - ESTRPIPE) {			int err;#ifdef ALSADEBUG			printf( "w:strpipe\n");#endif			while ((err = snd_pcm_resume(handle)) == -EAGAIN) {				printf( "w:::::resume failed, prepare\n");				usleep(100); 			}			if (err < 0) {				printf( "w:resume failed, prepare\n");				if (snd_pcm_prepare(handle) < 0) {					printf( "w:snd_pcm_prepare failed\n");					return false;				}			}			continue;		} else {			printf( "w:other problem\n");			if (snd_pcm_prepare(handle) < 0) {				printf( "w:snd_pcm_prepare failed\n");				return false;			}		}	}return true;}unsigned int DspOutAlsa::readableBytes( void ){	if( devstate != DeviceOpened ) {		return 0;	}	return 64;}bool DspOutAlsa::readBuffer( int bytes ){	if( devstate != DeviceOpened ) {		lasterror = "Device Not Open";		return false;	}	int rc;	size_t frames = audio_buf.getSize()/2;	frames=32;	audio_buf.resize( frames*2 );	void *buf;	buf = alloca(frames*4);	rc = snd_pcm_readi( handle, buf, frames );	if (rc == -EPIPE) {		snd_pcm_prepare( handle );		snd_pcm_start (handle);		printf( "error from read: EPIPE\n");		return true;	} else if (rc < 0) {		printf( "error from read: %s\n", snd_strerror(rc));		return false;	} else if (rc != (int)frames) {		printf("warning: asked microphone for %lu frames but got %lu\n",			(unsigned long)frames, (unsigned long)rc);		frames = rc;		audio_buf.resize( frames*2 );	}	int8_t *b1 = reinterpret_cast<int8_t*>(buf);	int8_t *b2 = reinterpret_cast<int8_t*>(audio_buf.getData());	for( size_t i=0; i < frames; i++ ) {		b2[2*i]   = b1[4*i];		b2[2*i+1] = b1[4*i+1];	}	return true;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -