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

📄 alsapmo.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*____________________________________________________________________________
        
        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(&params, 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, &params);

⌨️ 快捷键说明

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