📄 sound_alsa.cxx
字号:
if ((err = snd_pcm_hw_params_set_period_time_near (os_handle, hw_params, &period_time, 0)) < 0) {
msg << "Cannot set period_time to " << (period_time / 1000) << " ms " << snd_strerror (err);
PTRACE (1, "ALSA\t" << msg);
cerr << msg << endl;
}
if ((err = snd_pcm_hw_params (os_handle, hw_params)) < 0) {
msg << "Cannot set parameters " << snd_strerror (err);
PTRACE (1, "ALSA\t" << msg);
cerr << msg << endl;
no_error = FALSE;
}
isInitialised = TRUE;
return no_error;
}
BOOL PSoundChannelALSA::Close()
{
PWaitAndSignal m(device_mutex);
/* if the channel isn't open, do nothing */
if (!os_handle)
return FALSE;
snd_pcm_close (os_handle);
os_handle = NULL;
return TRUE;
}
BOOL PSoundChannelALSA::Write (const void *buf, PINDEX len)
{
long r = 0;
char *buf2 = (char *) buf;
int pos = 0, max_try = 0;
lastWriteCount = 0;
PWaitAndSignal m(device_mutex);
if (!isInitialised && !Setup(len) || !len || !os_handle)
return FALSE;
do {
/* the number of frames to read is the buffer length
divided by the size of one frame */
r = snd_pcm_writei (os_handle, (char *) &buf2 [pos], len / frameBytes);
if (r > 0) {
pos += r * frameBytes;
len -= r * frameBytes;
lastWriteCount += r * frameBytes;
}
else {
if (r == -EPIPE) { /* under-run */
r = snd_pcm_prepare (os_handle);
if (r < 0)
PTRACE (1, "ALSA\tCould not prepare device: " << snd_strerror (r));
} else if (r == -ESTRPIPE) {
while ((r = snd_pcm_resume (os_handle)) == -EAGAIN)
sleep(1); /* wait until the suspend flag is released */
if (r < 0)
snd_pcm_prepare (os_handle);
}
PTRACE (1, "ALSA\tCould not write " << max_try << " " << len << " " << r);
max_try++;
}
} while (len > 0 && max_try < 5);
return TRUE;
}
BOOL PSoundChannelALSA::Read (void * buf, PINDEX len)
{
long r = 0;
char *buf2 = (char *) buf;
int pos = 0, max_try = 0;
lastReadCount = 0;
PWaitAndSignal m(device_mutex);
if (!isInitialised && !Setup(len) || !len || !os_handle)
return FALSE;
memset ((char *) buf, 0, len);
do {
/* the number of frames to read is the buffer length
divided by the size of one frame */
r = snd_pcm_readi (os_handle, (char *) &buf2 [pos], len / frameBytes);
if (r > 0) {
pos += r * frameBytes;
len -= r * frameBytes;
lastReadCount += r * frameBytes;
}
else {
if (r == -EPIPE) { /* under-run */
snd_pcm_prepare (os_handle);
}
else if (r == -ESTRPIPE) {
while ((r = snd_pcm_resume (os_handle)) == -EAGAIN)
sleep(1); /* wait until the suspend flag is released */
if (r < 0)
snd_pcm_prepare (os_handle);
}
PTRACE (1, "ALSA\tCould not read");
max_try++;
}
} while (len > 0 && max_try < 5);
if (len != 0) {
memset ((char *) &buf2 [pos], 0, len);
lastReadCount += len;
PTRACE (1, "ALSA\tRead Error, filling with zeros");
}
return TRUE;
}
BOOL PSoundChannelALSA::SetFormat (unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
if (!os_handle)
return SetErrorValues(NotOpen, EBADF);
/* check parameters */
PAssert((bitsPerSample == 8) || (bitsPerSample == 16), PInvalidParameter);
PAssert(numChannels >= 1 && numChannels <= 2, PInvalidParameter);
mNumChannels = numChannels;
mSampleRate = sampleRate;
mBitsPerSample = bitsPerSample;
/* mark this channel as uninitialised */
isInitialised = FALSE;
return TRUE;
}
unsigned PSoundChannelALSA::GetChannels() const
{
return mNumChannels;
}
unsigned PSoundChannelALSA::GetSampleRate() const
{
return mSampleRate;
}
unsigned PSoundChannelALSA::GetSampleSize() const
{
return mBitsPerSample;
}
BOOL PSoundChannelALSA::SetBuffers (PINDEX size, PINDEX count)
{
storedPeriods = count;
storedSize = size;
return TRUE;
}
BOOL PSoundChannelALSA::GetBuffers(PINDEX & size, PINDEX & count)
{
size = storedSize;
count = storedPeriods;
return FALSE;
}
BOOL PSoundChannelALSA::PlaySound(const PSound & sound, BOOL wait)
{
if (!os_handle)
return SetErrorValues(NotOpen, EBADF);
if (!Write((const BYTE *)sound, sound.GetSize()))
return FALSE;
if (wait)
return WaitForPlayCompletion();
return TRUE;
}
BOOL PSoundChannelALSA::PlayFile(const PFilePath & filename, BOOL wait)
{
BYTE buffer [512];
if (!os_handle)
return SetErrorValues(NotOpen, EBADF);
PFile file (filename, PFile::ReadOnly);
if (!file.IsOpen())
return FALSE;
for (;;) {
if (!file.Read (buffer, 512))
break;
PINDEX len = file.GetLastReadCount();
if (len == 0)
break;
if (!Write(buffer, len))
break;
}
file.Close();
if (wait)
return WaitForPlayCompletion();
return TRUE;
}
BOOL PSoundChannelALSA::HasPlayCompleted()
{
if (!os_handle)
return SetErrorValues(NotOpen, EBADF);
return (snd_pcm_state (os_handle) != SND_PCM_STATE_RUNNING);
}
BOOL PSoundChannelALSA::WaitForPlayCompletion()
{
if (!os_handle)
return SetErrorValues(NotOpen, EBADF);
snd_pcm_drain (os_handle);
return TRUE;
}
BOOL PSoundChannelALSA::RecordSound(PSound & sound)
{
return FALSE;
}
BOOL PSoundChannelALSA::RecordFile(const PFilePath & filename)
{
return FALSE;
}
BOOL PSoundChannelALSA::StartRecording()
{
return FALSE;
}
BOOL PSoundChannelALSA::IsRecordBufferFull()
{
return TRUE;
}
BOOL PSoundChannelALSA::AreAllRecordBuffersFull()
{
return TRUE;
}
BOOL PSoundChannelALSA::WaitForRecordBufferFull()
{
return TRUE;
}
BOOL PSoundChannelALSA::WaitForAllRecordBuffersFull()
{
return FALSE;
}
BOOL PSoundChannelALSA::Abort()
{
int r = 0;
if (!os_handle)
return FALSE;
if ((r = snd_pcm_drain (os_handle)) < 0) {
PTRACE (1, "ALSA\tCannot abort" << snd_strerror (r));
return FALSE;
}
else
return TRUE;
}
BOOL PSoundChannelALSA::SetVolume (unsigned newVal)
{
unsigned i = 0;
return Volume (TRUE, newVal, i);
}
BOOL PSoundChannelALSA::GetVolume(unsigned &devVol)
{
return Volume (FALSE, 0, devVol);
}
BOOL PSoundChannelALSA::IsOpen () const
{
return (os_handle != NULL);
}
BOOL PSoundChannelALSA::Volume (BOOL set, unsigned set_vol, unsigned &get_vol)
{
int err = 0;
snd_mixer_t *handle;
snd_mixer_elem_t *elem;
snd_mixer_selem_id_t *sid;
const char *play_mix_name [] = { "PCM", "Master", "Speaker", NULL };
const char *rec_mix_name [] = { "Capture", "Mic", NULL };
PString card_name;
long pmin = 0, pmax = 0;
long int vol = 0;
int i = 0;
if (!os_handle)
return FALSE;
if (card_nr == -2)
card_name = "default";
else
card_name = "hw:" + PString (card_nr);
//allocate simple id
snd_mixer_selem_id_alloca (&sid);
//sets simple-mixer index and name
snd_mixer_selem_id_set_index (sid, 0);
if ((err = snd_mixer_open (&handle, 0)) < 0) {
PTRACE (1, "alsa-control: mixer open error: " << snd_strerror (err));
return FALSE;
}
if ((err = snd_mixer_attach (handle, card_name)) < 0) {
PTRACE (1, "alsa-control: mixer attach " << card_name << " error: " << snd_strerror(err));
snd_mixer_close(handle);
return FALSE;
}
if ((err = snd_mixer_selem_register (handle, NULL, NULL)) < 0) {
PTRACE (1, "alsa-control: mixer register error: " << snd_strerror(err));
snd_mixer_close(handle);
return FALSE;
}
err = snd_mixer_load(handle);
if (err < 0) {
PTRACE (1, "alsa-control: mixer load error: " << snd_strerror(err));
snd_mixer_close(handle);
return FALSE;
}
do {
snd_mixer_selem_id_set_name (sid, (direction == Player)?play_mix_name[i]:rec_mix_name[i]);
elem = snd_mixer_find_selem (handle, sid);
i++;
} while (!elem && ((direction == Player && play_mix_name[i] != NULL) || (direction == Recorder && rec_mix_name[i] != NULL)));
if (!elem) {
PTRACE (1, "alsa-control: unable to find simple control.");
snd_mixer_close(handle);
return FALSE;
}
if (set) {
if (direction == Player) {
snd_mixer_selem_get_playback_volume_range (elem, &pmin, &pmax);
vol = (set_vol * (pmax?pmax:31)) / 100;
snd_mixer_selem_set_playback_volume_all (elem, vol);
}
else {
snd_mixer_selem_get_capture_volume_range (elem, &pmin, &pmax);
vol = (set_vol * (pmax?pmax:31)) / 100;
snd_mixer_selem_set_capture_volume_all (elem, vol);
}
PTRACE (4, "Set volume to " << vol);
}
else {
if (direction == Player) {
snd_mixer_selem_get_playback_volume_range (elem, &pmin, &pmax);
snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &vol);
}
else {
snd_mixer_selem_get_capture_volume_range (elem, &pmin, &pmax);
snd_mixer_selem_get_capture_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &vol);
}
get_vol = (vol * 100) / (pmax?pmax:31);
PTRACE (4, "Got volume " << vol);
}
snd_mixer_close(handle);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -