📄 audlinux_alsa.cpp
字号:
m_unNumChannels = channels = numChannels; if ( numChannels != pFormat->uChannels ) { ((HXAudioFormat*)pFormat)->uChannels = numChannels; } int periods = 2; // Number of periods 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -