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

📄 audlinux_alsa.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  snd_pcm_uframes_t periodsize = 2048; // FIXME
  int direct=0;
  snd_pcm_uframes_t period = 0;

  // The period size == fragment size.
  // Note that this in frames (frame = nr_channels * sample_width)
  // So a value of 1024 means 4096 bytes (1024 x 2 x 16-bits)
        
  //     if((err = snd_pcm_hw_params_get_period_size_max( hwparams, &period,& direct) ) < 0)
  //       {
  // #ifdef _DEBUG
  //           printf("Unable to get period size %ld : %s\n", period,  snd_strerror(err));
  // #endif
  //       }
  //     direct=0;

  if((err = snd_pcm_hw_params_set_period_size_near( pcm_handle, hwparams, &periodsize, &direct) ) < 0)
    {
#ifdef _DEBUG
      printf("Set period size failed %ld : %s\n", periodsize,  snd_strerror(err));
#endif
    }


  //////////////////////////////////// set periods
  //      printf("set periods\n");
  //      if ((err = snd_pcm_hw_params_set_periods_near( pcm_handle, hwparams, &periods, &direct ))  < 0 )
  //        {
  //            printf("Error setting periods  %s\n", snd_strerror(err));
  //        }
 
  /*     if(( err =snd_pcm_hw_params_get_period_size( hwparams, &period_size, NULL)) < 0)
         {
         printf("unable to get peroidsize:\n") ;
         }
  */  
  //     snd_pcm_hw_params_get_period_size( hwparams, &val);



  //     if((err = snd_pcm_hw_params_set_buffer_size( pcm_handle, hwparams, bufferSz )) < 0)
  //      if((err = snd_pcm_hw_params_set_buffer_size_near( pcm_handle, hwparams, bufferSz )) < 0)
  //        {
  //            printf("Unable to set buffer size %li : %s\n", bufferSz, snd_strerror(err));
  //        }
  //     printf("get buffer size\n");

  ////////////////////////// Get buffer size in frames 
  //  m_wBlockSize = m_ulBytesPerGran;
  if((err = snd_pcm_hw_params_get_buffer_size_max( hwparams, &bufferSz)) < 0) 
    {
#ifdef _DEBUG
      printf("Get buffer size failed:\n") ;
#endif
      if(  m_ulDeviceBufferSize <= 0)
        blocksize = m_wBlockSize = m_ulDeviceBufferSize = 8192 * 2;
    }
  else
    {
      blocksize = bufferSz;
      m_wBlockSize = blocksize;
      m_ulDeviceBufferSize  = blocksize *  samplesize * channels;
    }
  //    printf("blocksize %d, samplesize %d, channels %d\n", blocksize, samplesize, channels );
  //    printf("m_ulDeviceBufferSize %ld\n",  m_ulDeviceBufferSize);

  
  if (snd_pcm_hw_params( pcm_handle, hwparams) < 0) //write device
    {
#ifdef _DEBUG
      fprintf(stderr, "Error setting HW params.\n");
#endif
      return ( m_wLastError = RA_AOE_NOTENABLED );
    }


  snd_pcm_sw_params_alloca(&swparams);

  if((err = snd_pcm_sw_params_current( pcm_handle, swparams)) <0)
    {
#ifdef _DEBUG
      printf("Current SW params failed: %s\n", snd_strerror(err));
#endif
    }

  //  if ((err = snd_pcm_sw_params_set_avail_min ( pcm_handle, swparams, 2048)) < 0) {
  //       fprintf (stderr, "cannot set minimum available count (%s)\n",
  //                snd_strerror (err));
  //   }

  if((err = snd_pcm_sw_params_set_start_threshold( pcm_handle, swparams, bufferSz )) < 0)
    {
#ifdef _DEBUG
      printf("Set start threshold mode failed: %s\n", snd_strerror(err));
#endif
    }

  if((err = snd_pcm_sw_params_set_xfer_align( pcm_handle, swparams, 1)) < 0)
    {
#ifdef _DEBUG
      printf("Set transfer align failed: %s\n", snd_strerror(err));
#endif
    } 

  if((err = snd_pcm_sw_params_set_tstamp_mode( pcm_handle, swparams,SND_PCM_TSTAMP_MMAP )) < 0 )
    {
#ifdef _DEBUG
      printf("Set sw params time stamp mode failed: %s\n", snd_strerror(err));
#endif
    }

  if((err = snd_pcm_sw_params( pcm_handle, swparams)) < 0)
    {
#ifdef _DEBUG
      printf("Set sw params failed: %s\n", snd_strerror(err));
#endif
    }

  if ((err=snd_pcm_prepare ( pcm_handle)) < 0)
    {
#ifdef _DEBUG
      fprintf (stderr, "Prepare audio interface failed %s\n",
               snd_strerror (err));
#endif
      return  retCode = RA_AOE_NOTENABLED;
    }       


#ifdef _DEBUG
  snd_output_t *output = NULL;
  snd_output_stdio_attach(&output, stdout, 0);
  printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
  snd_pcm_dump( pcm_handle, output);
  printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
  snd_pcm_hw_params_dump( hwparams, output);
  printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
  snd_pcm_sw_params_dump( swparams, output); 
  printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
  //     snd_pcm_status_dump( status, output);
  //     printf("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");

  fprintf( stdout, "Device Configured:\n");
  fprintf( stdout, "         Sample Rate: %d\n",  m_unSampleRate);
  fprintf( stdout, "        Sample Width: %d\n",  nSampleWidth);
  fprintf( stdout , "        Num channels: %d\n",  m_unNumChannels);
  fprintf( stdout, "          Block size: %d\n",  m_wBlockSize);
  fprintf( stdout, "  Device buffer size: %lu\n", m_ulDeviceBufferSize);

#endif

  //     snd_pcm_sw_params_free( swparams);

  return RA_AOE_NOERR;
}

void CAudioOutLinuxAlsa::_SyncUpTimeStamps(ULONG32 writeCount)
{
  snd_pcm_hwsync( pcm_handle);
  int bytes2  = 0;
  int err = 0;

  snd_pcm_sframes_t framedelay;

  if((err = snd_pcm_delay( pcm_handle, &framedelay)) < 0)
    {
#ifdef _DEBUG
      fprintf (stderr, "cannot get delay %s\n", snd_strerror (err));
#endif
    }

  bytes2 = snd_pcm_frames_to_bytes( pcm_handle, framedelay);
             
  if( bytes2 > 0)
    {
      m_ulLastBytesPlayed = (UINT64)( m_ulTotalWritten + writeCount - bytes2);
      m_ulLastTimeStamp   = GetTickCount();
    }
}


//Device specific method to write bytes out to the audiodevice and return a
//count of bytes written.
HX_RESULT CAudioOutLinuxAlsa::_WriteBytes( UCHAR* buffer, ULONG32 ulBuffLength, LONG32& lCount )
{
  LONG32 writeCount;
  HX_RESULT retCode = RA_AOE_NOERR;
  int err=0;
  if( m_ulTickCount == 0 )
    m_ulTickCount = GetTickCount();

  snd_pcm_sframes_t num_frames, size;

  lCount = 0;

  num_frames = snd_pcm_bytes_to_frames( pcm_handle, ulBuffLength); //alsa in frames

  // Returns the number of frames actually written. 
  size = snd_pcm_writei( pcm_handle, buffer, num_frames );

  if(size < 0)
    {
      switch (size)
        {
        case -EBADFD:
          {
#ifdef _DEBUG
            printf("EBADFD: Device not in the right state \n");
#endif
            retCode = RA_AOE_DEVBUSY;
          }
          break;
        case -EPIPE: //lets handle underruns
          {
            if(( size = snd_pcm_prepare( pcm_handle) ) < 0 )
              {
#ifdef _DEBUG
                printf("EPIPE: Recovery from underrun is difficult: %s\n", snd_strerror( size));
#endif
                retCode = RA_AOE_DEVBUSY;
              }
          }
          break;
        case -ESTRPIPE:
          {
            while (( size = snd_pcm_resume( pcm_handle)) == -EAGAIN)
              sleep(1);
            if ( size < 0)
              {
                size = snd_pcm_prepare( pcm_handle);
                if ( size < 0)
                  {
#ifdef _DEBUG
                    printf("ESTRPIPE: Recover from suspend is difficult: %s\n", snd_strerror( size));
#endif
                    retCode = RA_AOE_DEVBUSY;
                  }
              }
          }
          break;
        };
    }

//  printf("frames written = %d\n", size);
  writeCount = snd_pcm_frames_to_bytes( pcm_handle, size );

  if( writeCount < 0 )
    {
      if( errno == EAGAIN )
        retCode = RA_AOE_NOERR;
      if( errno == EINTR )
        retCode = RA_AOE_DEVBUSY;
    }
  else
    {
      _SyncUpTimeStamps( writeCount);

      // XXXRGG: Figure out why writeCount != ulBuffLength
      // lCount = writeCount;
      lCount = ulBuffLength;
    }

  return retCode;
}


UINT64 CAudioOutLinuxAlsa::_GetBytesActualyPlayed(void) const
{
  // Get current playback position in device DMA. 
  int     bytes2 = 0;
  UINT64  ulTheAnswer = 0;

  if( m_ulTotalWritten > 0 )
    {
      HX_ASSERT( m_unSampleRate!=0 && m_uSampFrameSize!=0 );
      ULONG32 ulTick = GetTickCount();
      //We need to update the timestamps every so often.
      //This make sure that if the XServer was blocked, and
      //we ran dry, that we re-sync up.
      if( (ulTick - m_ulLastTimeStamp) > 200 )
        {
          ((CAudioOutLinuxAlsa*)this)->_SyncUpTimeStamps();
          ulTick = GetTickCount();
        }
      ulTheAnswer = (UINT64)(m_ulLastBytesPlayed+
                             ((float)(ulTick-m_ulLastTimeStamp)*
                              (float)m_unNumChannels/1000.0*
                              m_unSampleRate*m_uSampFrameSize) +0.5 );
    }

  //    printf("BytesActualyPlayed %ld\n", ulTheAnswer);
  return  ulTheAnswer;
}


//this must return the number of bytes that can be written without blocking.
HX_RESULT CAudioOutLinuxAlsa::_GetRoomOnDevice(ULONG32& ulBytes) const
{
  HX_RESULT  retCode = RA_AOE_NOERR;

  // FIXME

  ulBytes = m_ulDeviceBufferSize - ( m_ulTotalWritten - _GetBytesActualyPlayed() );
  //    printf("RoomOnDevice %ld\n", ulBytes);
  m_wLastError = retCode;
  return m_wLastError;
}


//Device specific method to get/set the devices current volume.
UINT16 CAudioOutLinuxAlsa::_GetVolume() const
{

  UINT16 nRetVolume   = 0;
  long pmin = 0, pmax = 0;
  long percentage = 0;
  
  long frontLeftVolume = 0;
  long frontRightVolume = 0;
  
  /*  long frontCenterVolume = 0;

  long rearLeftVolume = 0;
  long rearRightVolume = 0;
  
  long wooferVolume = 0;

  snd_mixer_selem_id_t *sid;
  snd_mixer_selem_id_alloca(&sid);
  */
  snd_mixer_elem_t *mixer_elements2;

  mixer_elements2 = snd_mixer_first_elem( mixer_handle);
  // grab first elem of mixer
  if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
            
    if( snd_mixer_selem_get_playback_volume( mixer_elements2,
                                             SND_MIXER_SCHN_FRONT_LEFT, &frontLeftVolume) < 0)
      frontLeftVolume = 0;
           
    if( snd_mixer_selem_get_playback_volume( mixer_elements2,
                                             SND_MIXER_SCHN_FRONT_RIGHT, &frontRightVolume) < 0)
      frontRightVolume = 0;
  }

  /*    snd_mixer_selem_get_playback_volume_range( mixer_elements2, &pmin, &pmax);
        int range = pmax - pmin;
        int val = frontLeftVolume;
        frontRightVolume =  frontLeftVolume;
        val -= pmin;

        //    printf("min %d, max %d, range %d, val %d\n", pmin, pmax, range, val );
        percentage = (long)rint((double)val / (double)range * 100);
  */      

  //    printf("fleft %ld, fright %ld, percent %d\n",
  //           frontLeftVolume, frontRightVolume, percentage);


  // Save for future use, demonstrates multichannel mixer access.
  

  //   for ( mixer_elements2 = snd_mixer_first_elem( mixer_handle);
  //         mixer_elements2;
  //         mixer_elements2 = snd_mixer_elem_next( mixer_elements2) )  {
    
  //     snd_mixer_selem_get_id( mixer_elements2, sid);
    
  // //     if ( !snd_mixer_selem_is_active( mixer_elements2))
  // //       continue;
    
  //     printf("mixer control '%s',%i\n", 
  //     snd_mixer_selem_id_get_name( sid), 
  //     snd_mixer_selem_id_get_index( sid));
  
  //        snd_mixer_selem_get_playback_volume_range( mixer_elements2, &pmin, &pmax);
  //         // if its got mono mixer
  //        if ( snd_mixer_selem_has_common_volume( mixer_elements2)) //mono
  //      {
  //            // check for playback vol mixer         
  //          if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
  //                //score!        
  // //           if( snd_mixer_find_selem( mixer_handle,mixer_elements2) == SND_MIXER_SCHN_MONO)
  // //             {
  //              snd_mixer_selem_get_playback_volume( mixer_elements2,
  //                                                   SND_MIXER_SCHN_MONO, &frontLeftVolume);
  //                //for finding percentage
                
  //              int range = pmax - pmin;
  //              int val = frontLeftVolume;
  //              frontRightVolume =  frontLeftVolume;
  //              val -= pmin;
  //              percentage = (long)rint((double)val / (double)range * 100);
  //              printf("common min %d, max %d, range %d\n", pmin, pmax, range);
   
  //          }
  //      }
  //        else //stereo
  //       {
  // //          printf("get seperate r and l volumes\n");       
  //           if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
            
  //               if( snd_mixer_selem_get_playback_volume( mixer_elements2,
  //                                                        SND_MIXER_SCHN_FRONT_LEFT, &frontLeftVolume) < 0)
  //                   frontLeftVolume = 0;
           
  //               if( snd_mixer_selem_get_playback_volume( mixer_elements2,
  //                                                        SND_MIXER_SCHN_FRONT_RIGHT, &frontRightVolume) < 0)
  //                   frontRightVolume = 0;
              
  // //               if( snd_mixer_selem_get_playback_volume( mixer_elements2,
  // //                                                        SND_MIXER_SCHN_FRONT_CENTER, &frontCenterVolume) < 0)

⌨️ 快捷键说明

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