📄 alsapmo.cpp
字号:
{
m_iBaseTime = -1;
PhysicalMediaOutput::Pause();
}
bool AlsaPMO::WaitForDrain(void)
{
snd_pcm_playback_status_t ainfo;
snd_pcm_playback_status(ai->handle,&ainfo);
for(; !m_bExit && !m_bPause; )
{
snd_pcm_playback_status(ai->handle,&ainfo);
if (ainfo.underrun || ainfo.queue < ainfo.fragment_size)
{
return true;
}
WasteTime();
}
return false;
}
void AlsaPMO::HandleTimeInfoEvent(PMOTimeInfoEvent *pEvent)
{
MediaTimeInfoEvent *pmtpi;
int32 hours, minutes, seconds;
int iTotalTime = 0;
snd_pcm_playback_status_t ainfo;
long long llStart, llEnd;
if (m_iBaseTime < 0)
{
m_iBaseTime = (pEvent->GetFrameNumber() *
myInfo->samples_per_frame) /
myInfo->samples_per_second;
}
snd_pcm_playback_status(ai->handle,&ainfo);
llEnd = ((long long)ainfo.time.tv_sec * 100) +
((long long)ainfo.time.tv_usec / 10000);
llStart = ((long long)ainfo.stime.tv_sec * 100) +
((long long)ainfo.stime.tv_usec / 10000);
iTotalTime = ((llEnd - llStart) / 100) + m_iBaseTime;
iTotalTime %= 86400;
hours = iTotalTime / 3600;
minutes = (iTotalTime / 60) % 60;
seconds = iTotalTime % 60;
if (hours < 0 ||
minutes < 0 || minutes > 59 ||
seconds < 0 || seconds > 59)
return;
pmtpi = new MediaTimeInfoEvent(hours, minutes, seconds, 0,
iTotalTime, 0);
m_pTarget->AcceptEvent(pmtpi);
}
void AlsaPMO::StartWorkerThread(void *pVoidBuffer)
{
((AlsaPMO*)pVoidBuffer)->WorkerThread();
}
void AlsaPMO::WorkerThread(void)
{
void *pBuffer;
Error eErr;
size_t iRet;
Event *pEvent;
snd_pcm_playback_status_t ainfo;
// Don't do anything until resume is called.
m_pPauseSem->Wait();
// Sleep for a pre buffer period
PreBuffer();
// The following should be abstracted out into the general thread
// classes:
#ifdef __linux__
struct sched_param sParam;
sParam.sched_priority = sched_get_priority_max(SCHED_OTHER);
pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam);
#endif
for(; !m_bExit;)
{
if (m_bPause)
{
m_pPauseSem->Wait();
continue;
}
// Loop until we get an Init event from the LMC
if (!m_properlyInitialized)
{
pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();
if (pEvent == NULL)
{
m_pLmc->Wake();
WasteTime();
continue;
}
if (pEvent->Type() == PMO_Init)
{
if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
{
delete pEvent;
break;
}
}
delete pEvent;
continue;
}
// Set up reading a block from the buffer. If not enough bytes are
// available, sleep for a little while and try again.
for(;;)
{
eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer,
m_iDataSize);
if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
break;
if (eErr == kError_NoDataAvail)
{
m_pLmc->Wake();
WasteTime();
continue;
}
// Is there an event pending that we need to take care of
// before we play this block of samples?
if (eErr == kError_EventPending)
{
pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();
if (pEvent->Type() == PMO_Init)
Init(((PMOInitEvent *)pEvent)->GetInfo());
if (pEvent->Type() == PMO_Reset)
Reset(false);
if (pEvent->Type() == PMO_Info)
HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);
if (pEvent->Type() == PMO_Quit)
{
delete pEvent;
if (WaitForDrain())
{
Reset(true);
m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
}
return;
}
delete pEvent;
continue;
}
if (IsError(eErr))
{
ReportError("Internal error occured.");
m_pContext->log->Error("Cannot read from buffer in PMO "
"worker tread: %d\n", eErr);
break;
}
break;
}
// Now write the block to the audio device. If the block doesn't
// all fit, pause and loop until the entire block has been played.
// This loop could be written using non-blocking io...
for(;;)
{
if (m_bExit || m_bPause)
break;
iRet = snd_pcm_playback_status(ai->handle,&ainfo);
if (ainfo.count < m_iDataSize)
{
WasteTime();
continue;
}
break;
}
if (m_bExit || m_bPause)
{
m_pInputBuffer->EndRead(0);
continue;
}
iRet = snd_pcm_write(ai->handle,pBuffer,m_iDataSize);
if (iRet < 0)
{
m_pInputBuffer->EndRead(0);
ReportError("Could not write sound data to the soundcard.");
m_pContext->log->Error("Failed to write to the soundcard: %s\n",
strerror(errno));
break;
}
m_pInputBuffer->EndRead(iRet);
m_pLmc->Wake();
UpdateBufferStatus();
}
}
int AlsaPMO::audio_set_all(struct audio_info_struct *ai)
{
int err;
if(ai->format == -1) {
#ifdef DEBUG
cout<<"AlsaPMO::audio_set_all:ai->format error"<<endl;
#endif
return 0;
}
if(!ai || ai->rate < 0) {
#ifdef DEBUG
cout<<"AlsaPMO::audio_set_all:ai->rate error"<<endl;
#endif
return -1;
}
if(ai->alsa_format.channels < 0) {
#ifdef DEBUG
cout<<"AlsaPMO::audio_set_all:ai->channels error"<<endl;
#endif
return 0;
}
#ifdef DEBUG
cout<<"AlsaPMO::audio_set_all: format="<<ai->format<<",rate="<<ai->rate<<",channels="<<ai->channels<<endl;
#endif
switch(ai->format)
{
case AUDIO_FORMAT_SIGNED_16:
default:
ai->alsa_format.format=SND_PCM_SFMT_S16_LE;
break;
case AUDIO_FORMAT_UNSIGNED_8:
ai->alsa_format.format=SND_PCM_SFMT_U8;
break;
case AUDIO_FORMAT_SIGNED_8:
ai->alsa_format.format=SND_PCM_SFMT_S8;
break;
case AUDIO_FORMAT_ULAW_8:
ai->alsa_format.format=SND_PCM_SFMT_MU_LAW;
break;
case AUDIO_FORMAT_ALAW_8:
ai->alsa_format.format=SND_PCM_SFMT_A_LAW;
break;
case AUDIO_FORMAT_UNSIGNED_16:
ai->alsa_format.format=SND_PCM_SFMT_U16_LE;
break;
}
// ai->alsa_format.format=SND_PCM_SFMT_S16_LE;
ai->alsa_format.rate=ai->rate;
ai->alsa_format.channels = ai->channels;
if((err=snd_pcm_playback_format(ai->handle, &ai->alsa_format)) < 0 ) {
// ReportError("Cannot reset the soundcard.");
ReportError("Cannot get audio format.");
return (Error)pmoError_IOCTL_SNDCTL_DSP_RESET;
}
// audio_set_playback_params2(ai);
// int err;
snd_pcm_playback_info_t pi;
snd_pcm_playback_params_t pp;
if((err=snd_pcm_playback_info(ai->handle, &pi)) < 0 )
{
ReportError("Cannot get audio info.");
return (Error)pmoError_ALSA_Playback_Info;
}
bzero(&pp, sizeof(pp));
pp.fragment_size = pi.buffer_size/4;
if ((unsigned)pp.fragment_size > pi.max_fragment_size)
pp.fragment_size = pi.max_fragment_size;
if ((unsigned)pp.fragment_size < pi.min_fragment_size)
pp.fragment_size = pi.min_fragment_size;
pp.fragments_max = -1;
pp.fragments_room = 1;
if((err=snd_pcm_playback_params(ai->handle, &pp)) < 0 )
{
ReportError("Cannot set audio params.");
return (Error)pmoError_ALSA_Playback_Params;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -