📄 alsapmo.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Driver for Advanced Linux Sound Architecture
http://www.alsa-project.org
Portions Copyright (C) 1998-1999 EMusic.com
alsapmo.cpp by Fleischer Gabor <flocsy@usa.net>
uses code by Anders Semb Hermansen <ahermans@vf.telia.no>
and Jaroslav Kysela <perex@jcu.cz>
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.
$Id: alsapmo.cpp,v 1.33 2000/10/19 17:04:10 robert Exp $
____________________________________________________________________________*/
/* system headers */
#include <stdlib.h>
#include <iostream.h>
#include <sys/asoundlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
/* project headers */
#include <config.h>
#include "alsapmo.h"
#include "facontext.h"
#include "log.h"
#define DB printf("%s:%d\n", __FILE__, __LINE__);
extern "C"
{
PhysicalMediaOutput *Initialize(FAContext *context) {
return new AlsaPMO(context);
}
}
static int parse_gid(const char *str, snd_mixer_gid_t *gid)
{
unsigned int size;
unsigned char *ptr;
bzero(gid, sizeof(*gid));
ptr = gid->name;
size = 0;
while (*str) {
if (size < sizeof(gid->name)) {
*ptr++ = *str;
size++;
}
str++;
}
return 0;
}
AlsaPMO::AlsaPMO(FAContext *context) :
PhysicalMediaOutput(context)
{
uint32 deviceNameSize = 128;
char scard[128];
snd_mixer_t *pMixer;
char mixer_id[25]="Master";
m_properlyInitialized = false;
myInfo = new OutputInfo();
memset(myInfo, 0, sizeof(OutputInfo));
m_pBufferThread = NULL;
m_iOutputBufferSize = 0;
m_iBytesPerSample = 0;
m_iBaseTime = -1;
m_iDataSize = 0;
if (!m_pBufferThread)
{
m_pBufferThread = Thread::CreateThread();
assert(m_pBufferThread);
m_pBufferThread->Create(AlsaPMO::StartWorkerThread, this);
}
m_handle = NULL;
m_device = NULL;
m_channels = -1;
m_rate = -1;
m_device = (char *) malloc(deviceNameSize);
m_pContext->prefs->GetPrefString(kALSADevicePref, m_device,
&deviceNameSize);
if (m_device)
{
if (sscanf(m_device, "%[^:]: %d", scard, &m_iDevice) != 2)
{
ReportError("The ALSADevice statement in the preference file"
"is improperly formatted. Format: ALSADevice: "
"[card name/card number]:[device number]");
return;
}
m_iCard = snd_card_name(scard);
if (m_iCard < 0)
{
ReportError("Invalid ALSA card name/number specified.");
return;
}
if (m_iDevice < 0 || m_iDevice > 31)
{
ReportError("Invalid ALSA device number specified.");
return;
}
}
else
m_iCard = m_iDevice = 0;
switch (m_iDevice)
{
case 0:
strncpy(mixer_id,"PCM",sizeof(mixer_id));
break;
case 1:
strncpy(mixer_id,"PCM1",sizeof(mixer_id));
break;
}
parse_gid(mixer_id, &m_gid);
snd_mixer_open(&pMixer, m_iCard, 0);
bzero(&m_group, sizeof(m_group));
m_group.gid = m_gid;
if ((m_iChannel = snd_mixer_group_read(pMixer, &m_group )) < 0)
{
strncpy(mixer_id,"Master",sizeof(mixer_id));
parse_gid(mixer_id, &m_gid);
m_group.gid = m_gid;
m_iChannel = snd_mixer_group_read(pMixer, &m_group );
}
snd_mixer_close(pMixer);
delete m_device;
}
AlsaPMO::~AlsaPMO()
{
m_bExit = true;
m_pSleepSem->Signal();
m_pPauseSem->Signal();
if (m_pBufferThread)
{
m_pBufferThread->Join();
delete m_pBufferThread;
}
snd_pcm_close(m_handle);
if (myInfo) {
delete myInfo;
myInfo = NULL;
}
}
void AlsaPMO::SetVolume(int32 left, int32 right)
{
int err;
snd_mixer_t *pMixer;
err = snd_mixer_open(&pMixer, m_iCard, 0);
if (err < 0)
return;
if (m_iChannel >= 0)
{
err = snd_mixer_group_read(pMixer, &m_group);
if (err < 0)
return;
left = (int)((double)(m_group.max - m_group.min) *
(double)left * 0.01) + m_group.min;
right = (int)((double)(m_group.max - m_group.min) *
(double)right * 0.01) + m_group.min;
for (int chn = 0; chn <= SND_MIXER_CHN_LAST; chn++) {
if (!(m_group.channels & (1<<chn)))
continue;
if (chn == 0)
m_group.volume.values[chn] = left;
else
if (chn == 1)
m_group.volume.values[chn] = right;
else
m_group.volume.values[chn] = (left + right) / 2;
}
snd_mixer_group_write(pMixer, &m_group);
}
snd_mixer_close(pMixer);
}
void AlsaPMO::GetVolume(int32 &left, int32 &right)
{
int err;
snd_mixer_t *pMixer = NULL;
err = snd_mixer_open(&pMixer, m_iCard, 0);
if (err != 0)
{
return;
}
if (m_iChannel >= 0)
{
err = snd_mixer_group_read(pMixer, &m_group);
if (err < 0)
return;
}
else
return;
snd_mixer_close(pMixer);
left = (int)(((float)((m_group.volume.values[0] - m_group.min) * 100) /
(float)(m_group.max - m_group.min)) + 0.5);
right = (int)(((float)((m_group.volume.values[1] - m_group.min) * 100) /
(float)(m_group.max - m_group.min)) + 0.5);
}
Error AlsaPMO::Init(OutputInfo* info)
{
int err;
snd_pcm_channel_params_t params;
m_properlyInitialized = false;
if (!info)
{
info = myInfo;
}
else
{
// got info, so this is the beginning...
m_iDataSize = info->max_buffer_size;
err=snd_pcm_open(&m_handle, m_iCard, m_iDevice,
SND_PCM_OPEN_PLAYBACK);
if (err < 0)
{
ReportError("Audio device is busy. Please make sure that "
"another program is not using the device.");
return (Error)pmoError_DeviceOpenFailed;
}
snd_pcm_nonblock_mode(m_handle, 1);
}
// configure the device:
m_channels=info->number_of_channels;
m_rate=info->samples_per_second;
memset(¶ms, 0, sizeof(params));
params.format.format = SND_PCM_SFMT_S16_LE;
params.format.interleave = 1;
params.format.voices = m_channels;
params.format.rate = info->samples_per_second;
params.channel = SND_PCM_CHANNEL_PLAYBACK;
params.mode = SND_PCM_MODE_BLOCK;
params.start_mode = SND_PCM_START_DATA;
params.stop_mode = SND_PCM_STOP_STOP;
params.buf.block.frag_size = m_iDataSize;
params.buf.block.frags_max = 32;
params.buf.block.frags_min = 1;
err = snd_pcm_channel_params(m_handle, ¶ms);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -