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

📄 qsa.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/*
 * qsa.cxx
 *
 * QNX Sound Architecture
 */

#pragma implementation "sound.h"

#include <ptlib.h>
#include <stdio.h>
#include <sys/asoundlib.h>

typedef struct _SoundHandleEntry {
	struct _SoundHandleEntry *next;
	
	int handle;
	int direction;

	unsigned numChannels;
	unsigned sampleRate;
	unsigned bitsPerSample;
	unsigned fragmentValue;
	BOOL isInitialised;
	
	snd_pcm_t   *pcm_handle;
	int         card;
	int         dev;
	snd_mixer_t *mixer_handle;
	snd_mixer_group_t group;
} SoundHandleEntry;

static SoundHandleEntry *SoundHandleList;
static pthread_rwlock_t SoundHandleLock = PTHREAD_RWLOCK_INITIALIZER;

static int snd_openmode[2] = {SND_PCM_OPEN_CAPTURE, SND_PCM_OPEN_PLAYBACK};
static int snd_chnmode[2]  = {SND_PCM_CHANNEL_CAPTURE, SND_PCM_CHANNEL_PLAYBACK};

PSound::PSound(unsigned channels,
               unsigned samplesPerSecond,
               unsigned bitsPerSample,
               PINDEX   bufferSize,
               const BYTE * buffer)
{
	encoding = 0;
	numChannels = channels;
	sampleRate = samplesPerSecond;
	sampleSize = bitsPerSample;
	SetSize(bufferSize);
	if (buffer != NULL)
	  memcpy(GetPointer(), buffer, bufferSize);
}


PSound::PSound(const PFilePath & filename)
{
	encoding = 0;
	numChannels = 1;
	sampleRate = 8000;
	sampleSize = 16;
	Load(filename);
}


PSound & PSound::operator=(const PBYTEArray & data)
{
	PBYTEArray::operator=(data);
	return *this;
}


void PSound::SetFormat(unsigned channels,
                       unsigned samplesPerSecond,
                       unsigned bitsPerSample)
{
	encoding = 0;
	numChannels = channels;
	sampleRate = samplesPerSecond;
	sampleSize = bitsPerSample;
	formatInfo.SetSize(0);
}


BOOL PSound::Load(const PFilePath & /*filename*/)
{
	return FALSE;
}


BOOL PSound::Save(const PFilePath & /*filename*/)
{
	return FALSE;
}


BOOL PSound::Play()
{
	PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
						  PSoundChannel::Player);
	if (!channel.IsOpen())
	  return FALSE;
	
	return channel.PlaySound(*this, TRUE);
}


BOOL PSound::PlayFile(const PFilePath & file, BOOL wait)
{
	PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
						  PSoundChannel::Player);
	if (!channel.IsOpen())
	  return FALSE;
	
	return channel.PlayFile(file, wait);
}


PSoundChannel::PSoundChannel()
{
	Construct();
}


PSoundChannel::PSoundChannel(const PString & device,
                             Directions dir,
                             unsigned numChannels,
                             unsigned sampleRate,
                             unsigned bitsPerSample)
{
	Construct();
	Open(device, dir, numChannels, sampleRate, bitsPerSample);
}


void PSoundChannel::Construct()
{
	os_handle = -1;
}


PSoundChannel::~PSoundChannel()
{
	Close();
}


PStringArray PSoundChannel::GetDeviceNames(Directions dir)
{
	PStringList devices;
	PDirectory  devdir = "/dev/snd";
	
	if (!devdir.Open())
	  return NULL;

	do {
		PString filename = devdir.GetEntryName();
		PString devname = devdir + filename;

		if ((filename.GetLength() > 3) && (filename.Left(3) == "pcm") &&
			(filename.Right(1) == (dir == Recorder ? "r" : "p")))
		{
			int fd = ::open(filename, O_RDONLY);
			if (fd >= 0) {
				devices.AppendString(filename);
				::close(fd);
			}
		}
	} while (devdir.Next());
	return devices;
}


PString PSoundChannel::GetDefaultDevice(Directions dir)
{
	PString filename;
	
	if (dir == Player)
	  filename = "/dev/snd/pcmPreferredp";
	else
	  filename = "/dev/snd/pcmPreferredc";
	
	int fd = ::open(filename, O_RDONLY);
//	PTRACE(1, "GetDefaultDevice; fd = " << fd << ", filename ='" << filename <<"'\n");
	if (fd >=0) {
		::close (fd);
		return filename;
	} else {
		return (filename = "/dev/null");
	}
}


BOOL PSoundChannel::Open(const PString & _device,
						 Directions _dir,
						 unsigned _numChannels,
						 unsigned _sampleRate,
						 unsigned _bitsPerSample)
{
	Close();
	
	// make the direction value 1 or 2
	int dir = _dir + 1;

	SoundHandleEntry *entry;
	
	pthread_rwlock_wrlock(&SoundHandleLock);
	for (entry = SoundHandleList; entry && entry->handle != os_handle; entry = entry->next);
	
	if (entry) {

		PTRACE(6, "OSS\tOpen occured for existing entry");
		
		// see if the sound channel is already open in this direction
		if ((entry->direction & dir) != 0) {
			pthread_rwlock_unlock(&SoundHandleLock);
			return FALSE;
		}
		
		// flag this entry as open in this direction
		entry->direction |= dir;
		os_handle = entry->handle;
	} else {
		
		PTRACE(6, "OSS\tOpen occured for new entry");
		
		SoundHandleEntry *entry = (SoundHandleEntry *)::malloc(sizeof(*entry));
		
		if (!entry) {
			pthread_rwlock_unlock(&SoundHandleLock);
			return FALSE;
		}

		// this is the first time this device has been used
		// open the device in read/write mode always
		if (((_dir == Player) && _device == "/dev/snd/pcmPreferredp") ||
			((_dir == Recorder) && _device == "/dev/snd/pcmPreferredc"))
		{
			os_handle = snd_pcm_open_preferred(&entry->pcm_handle, &entry->card, &entry->dev, snd_openmode[_dir]);
		} else {
			if (sscanf(_device, "/dev/snd/pcmC%iD%i", &entry->card, &entry->dev) != 2) {
				errno = ESRCH;
				return ConvertOSError(os_handle);
			}
			os_handle = snd_pcm_open(&entry->pcm_handle, entry->card, entry->dev, snd_openmode[_dir]);
		}
		
		if (os_handle < 0) {
			errno = -os_handle;
			os_handle = 0;
			return ConvertOSError(os_handle);
		}

		if (snd_pcm_plugin_set_disable(entry->pcm_handle, PLUGIN_DISABLE_MMAP) < 0)
		  return FALSE;
	
		// save the information into the dictionary entry
		os_handle            = snd_pcm_file_descriptor(entry->pcm_handle, snd_chnmode[_dir]);
		entry->handle        = os_handle;
		entry->direction     = dir;
		entry->numChannels   = mNumChannels     = _numChannels;
		entry->sampleRate    = actualSampleRate = mSampleRate    = _sampleRate;
		entry->bitsPerSample = mBitsPerSample   = _bitsPerSample;
		entry->isInitialised = FALSE;
		entry->fragmentValue = 0x7fff0008;
		entry->mixer_handle  = 0;
		
		entry->next          = SoundHandleList;
		SoundHandleList      = entry;
	}
	pthread_rwlock_unlock(&SoundHandleLock);
	
	// save the direction and device
	direction     = _dir;
	device        = _device;
	isInitialised = FALSE;
	
	return TRUE;
}

BOOL PSoundChannel::Setup()
{
	if (os_handle < 0) {
		PTRACE(6, "OSS\tSkipping setup of " << device << " as not open");
		return FALSE;
	}
	
	if (isInitialised) {
		PTRACE(6, "OSS\tSkipping setup of " << device << " as instance already initialised");
		return TRUE;
	}

	SoundHandleEntry *entry;
	pthread_rwlock_rdlock(&SoundHandleLock);
	for (entry = SoundHandleList; entry && entry->handle != os_handle;
		 entry = entry->next);
	
	// set default return status
	BOOL stat = TRUE;
	
	// do not re-initialise initialised devices
	if (entry->isInitialised) {
		pthread_rwlock_unlock(&SoundHandleLock);
		PTRACE(6, "OSS\tSkipping setup for " << device << " as already initialised");
		return stat;
	}
	
	PTRACE(6, "OSS\tInitialising " << device << "(" << (void *)(&entry) << ")");

    stat = FALSE;
	
	mBitsPerSample = entry->bitsPerSample;
	mNumChannels = entry->numChannels;
	mSampleRate = entry->sampleRate;

	snd_pcm_channel_params_t pp;

	memset(&pp, 0, sizeof(pp));
	pp.channel = snd_chnmode[direction];
	pp.mode = SND_PCM_MODE_BLOCK;
	pp.start_mode = (direction == Player) ? SND_PCM_START_FULL : SND_PCM_START_DATA;
	pp.stop_mode = SND_PCM_STOP_STOP;
	pp.buf.block.frags_min = 1;
	pp.buf.block.frag_size = 1 << (entry->fragmentValue & 0xffff);
	pp.buf.block.frags_max = ((unsigned)entry->fragmentValue >> 16) & 0x7fff;
	if (pp.buf.block.frags_max == 0)
	  pp.buf.block.frags_max = 65536;
		
	pp.format.interleave = 1;
	pp.format.rate = entry->sampleRate;
	pp.format.voices = entry->numChannels;
		
#if PBYTE_ORDER == PLITTLE_ENDIAN
	pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_LE : SND_PCM_SFMT_U8;
#else
	pp.format.format = (entry->bitsPerSample == 16) ? SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_U8;
#endif
	
	if (snd_pcm_plugin_params(entry->pcm_handle, &pp) < 0) {
		pthread_rwlock_unlock(&SoundHandleLock);
		return stat;
	}
	
	if (snd_pcm_plugin_prepare(entry->pcm_handle, snd_chnmode[direction]) < 0) {
		pthread_rwlock_unlock(&SoundHandleLock);
		return stat;
	}
	
	/* also open the mixer */
	snd_pcm_channel_setup_t setup;
	
	memset(&setup, 0, sizeof(setup));
	memset(&entry->group, 0, sizeof(entry->group));
	setup.channel = snd_chnmode[direction];
	setup.mixer_gid = &entry->group.gid;
	
	if (snd_pcm_plugin_setup(entry->pcm_handle, &setup) < 0) {
		pthread_rwlock_unlock(&SoundHandleLock);
		return FALSE;
	}
		
	if (snd_mixer_open(&entry->mixer_handle, entry->card, setup.mixer_device) < 0) {
		pthread_rwlock_unlock(&SoundHandleLock);
		return FALSE;
	}
	
	actualSampleRate = setup.format.rate;
	stat = TRUE;

#if PTRACING
	PTRACE(4, "QSA: Frag Size = " << setup.buf.block.frag_size
			   << ", Rate = " << setup.format.rate
		       << ", Mixer Pcm Group [" << entry->group.gid.name << "]\n");
#endif

	pthread_rwlock_unlock(&SoundHandleLock);
	// ensure device is marked as initialised
	isInitialised        = TRUE;
	entry->isInitialised = TRUE;
	
	return stat;
}

BOOL PSoundChannel::Close()
{
	// if the channel isn't open, do nothing
	if (os_handle < 0)
	  return TRUE;
	
	SoundHandleEntry *entry, **entryp;
	
	pthread_rwlock_wrlock(&SoundHandleLock);
	for (entryp = &SoundHandleList, entry = *entryp; entry && entry->handle != os_handle;
		 entryp = &entry->next, entry = *entryp);
	  
	if (!entry) {
		pthread_rwlock_unlock(&SoundHandleLock);
		return TRUE;
	}
	
	// modify the directions bit mask in the dictionary
	entry->direction ^= (direction+1);
	
	// if this is the last usage of this entry, then remove it
	if (entry->direction == 0) {
		snd_mixer_close(entry->mixer_handle);
		snd_pcm_plugin_flush(entry->pcm_handle, snd_chnmode[direction]);
		snd_pcm_close(entry->pcm_handle);
		*entryp = entry->next;
		::free(entry);
		os_handle = -1;
		pthread_rwlock_unlock(&SoundHandleLock);
		return PChannel::Close();
	}
	
	// flag this channel as closed
	pthread_rwlock_unlock(&SoundHandleLock);
	return TRUE;
}

BOOL PSoundChannel::Write(const void * buf, PINDEX len)
{
	if (!Setup())
	  return FALSE;
	
	if (os_handle < 0)
	  return FALSE;
	
	SoundHandleEntry * entry;
	pthread_rwlock_rdlock(&SoundHandleLock);
	for (entry = SoundHandleList; entry && entry->handle != os_handle;
		 entry = entry->next);
	
	snd_pcm_channel_status_t status;
	int written = 0;
	
	while ((written += snd_pcm_plugin_write(entry->pcm_handle, buf, len)) < len)
	{
		memset(&status, 0, sizeof(status));
		status.channel = SND_PCM_CHANNEL_PLAYBACK;
		if (snd_pcm_plugin_status(entry->pcm_handle, &status) < 0) {
			pthread_rwlock_unlock(&SoundHandleLock);

⌨️ 快捷键说明

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