// cae_alsa.cpp // // The ALSA Driver for the Core Audio Engine component of Rivendell // // (C) Copyright 2002-2019 Fred Gleason // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // 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. // #include #include #include #include #include #include #include #include #include #ifdef ALSA // // Callback Variables // volatile int alsa_input_channels[RD_MAX_CARDS][RD_MAX_PORTS]; volatile int alsa_output_channels[RD_MAX_CARDS][RD_MAX_STREAMS]; RDMeterAverage *alsa_input_meter[RD_MAX_CARDS][RD_MAX_PORTS][2]; RDMeterAverage *alsa_output_meter[RD_MAX_CARDS][RD_MAX_PORTS][2]; RDMeterAverage *alsa_stream_output_meter[RD_MAX_CARDS][RD_MAX_STREAMS][2]; volatile double alsa_input_volume[RD_MAX_CARDS][RD_MAX_PORTS]; volatile double alsa_output_volume[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS]; volatile double alsa_passthrough_volume[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_PORTS]; volatile double alsa_input_vox[RD_MAX_CARDS][RD_MAX_PORTS]; RDRingBuffer *alsa_play_ring[RD_MAX_CARDS][RD_MAX_STREAMS]; RDRingBuffer *alsa_record_ring[RD_MAX_CARDS][RD_MAX_PORTS]; RDRingBuffer *alsa_passthrough_ring[RD_MAX_CARDS][RD_MAX_PORTS]; volatile bool alsa_playing[RD_MAX_CARDS][RD_MAX_STREAMS]; volatile bool alsa_stopping[RD_MAX_CARDS][RD_MAX_STREAMS]; volatile bool alsa_eof[RD_MAX_CARDS][RD_MAX_STREAMS]; volatile int alsa_output_pos[RD_MAX_CARDS][RD_MAX_STREAMS]; volatile bool alsa_recording[RD_MAX_CARDS][RD_MAX_PORTS]; volatile bool alsa_ready[RD_MAX_CARDS][RD_MAX_PORTS]; void *AlsaCaptureCallback(void *ptr) { char alsa_buffer[RINGBUFFER_SIZE]; int modulo; int16_t in_meter[RD_MAX_PORTS][2]; struct alsa_format *alsa_format=(struct alsa_format *)ptr; signal(SIGTERM,SigHandler); signal(SIGINT,SigHandler); while(!alsa_format->exiting) { int s=snd_pcm_readi(alsa_format->pcm,alsa_format->card_buffer, rd_config->alsaPeriodSize()/(alsa_format->periods*2)); if(((snd_pcm_state(alsa_format->pcm)!=SND_PCM_STATE_RUNNING)&& (!alsa_format->exiting))||(s<0)) { snd_pcm_drop (alsa_format->pcm); snd_pcm_prepare(alsa_format->pcm); RDApplication::syslog(rd_config,LOG_DEBUG, "****** ALSA Capture Xrun - Card: %d ******", alsa_format->card); } else { switch(alsa_format->format) { case SND_PCM_FORMAT_S16_LE: modulo=alsa_format->channels; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_recording[alsa_format->card][i]) { if(alsa_input_volume[alsa_format->card][i]!=0.0) { switch(alsa_input_channels[alsa_format->card][i]) { case 1: for(int k=0;k<(2*s);k++) { ((int16_t *)alsa_buffer)[k]= (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+2*i]))+ (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+2*i+1])); } alsa_record_ring[alsa_format->card][i]-> write(alsa_buffer,s*sizeof(int16_t)); break; case 2: for(int k=0;kcard][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+2*i])); ((int16_t *)alsa_buffer)[2*k+1]= (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+2*i+1])); } alsa_record_ring[alsa_format->card][i]-> write(alsa_buffer,s*2*sizeof(int16_t)); break; } } } } // // Process Passthroughs // for(unsigned i=0;ichannels;i+=2) { for(unsigned j=0;j<2;j++) { for(int k=0;kpassthrough_buffer)[2*k+j]= ((int16_t *)alsa_format-> card_buffer)[alsa_format->channels*k+i+j]; } } alsa_passthrough_ring[alsa_format->card][i/2]-> write(alsa_format->passthrough_buffer,4*s); } // // Process Input Meters // for(unsigned i=0;ichannels;i+=2) { for(unsigned j=0;j<2;j++) { in_meter[i/2][j]=0; for(int k=0;k card_buffer)[alsa_format->channels*k+2*i+j]> in_meter[i][j]) { in_meter[i][j]= ((int16_t *)alsa_format-> card_buffer)[alsa_format->channels*k+2*i+j]; } } alsa_input_meter[alsa_format->card][i/2][j]-> addValue(((double)in_meter[i/2][j])/32768.0); } } break; case SND_PCM_FORMAT_S32_LE: modulo=alsa_format->channels*2; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_recording[alsa_format->card][i]) { if(alsa_input_volume[alsa_format->card][i]!=0.0) { switch(alsa_input_channels[alsa_format->card][i]) { case 1: for(int k=0;k<(2*s);k++) { ((int16_t *)alsa_buffer)[k]= (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+4*i+1]))+ (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format-> card_buffer) [modulo*k+4*i+3])); } alsa_record_ring[alsa_format->card][i]-> write(alsa_buffer,s*sizeof(int16_t)); break; case 2: for(int k=0;kcard][i]* (double)(((int16_t *)alsa_format->card_buffer) [modulo*k+4*i+1])); ((int16_t *)alsa_buffer)[2*k+1]= (int16_t)(alsa_input_volume[alsa_format->card][i]* (double)(((int16_t *)alsa_format->card_buffer) [modulo*k+4*i+3])); } alsa_record_ring[alsa_format->card][i]-> write(alsa_buffer,s*2*sizeof(int16_t)); break; } } } } // // Process Passthroughs // for(unsigned i=0;ichannels;i+=2) { for(unsigned j=0;j<2;j++) { for(int k=0;kpassthrough_buffer)[2*k+j]= ((int32_t *)alsa_format-> card_buffer)[alsa_format->channels*k+i+j]; } } alsa_passthrough_ring[alsa_format->card][i/2]-> write(alsa_format->passthrough_buffer,8*s); } // // Process Input Meters // for(unsigned i=0;ichannels;i+=2) { for(unsigned j=0;j<2;j++) { in_meter[i/2][j]=0; for(int k=0;k card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]> in_meter[i/2][j]) { in_meter[i/2][j]= ((int16_t *)alsa_format-> card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]; } } alsa_input_meter[alsa_format->card][i/2][j]-> addValue(((double)in_meter[i/2][j])/32768.0); } } break; default: break; } } } return 0; } void *AlsaPlayCallback(void *ptr) { int n=0; int p; char alsa_buffer[RINGBUFFER_SIZE]; int modulo; int16_t out_meter[RD_MAX_PORTS][2]; int16_t stream_out_meter=0; struct alsa_format *alsa_format=(struct alsa_format *)ptr; signal(SIGTERM,SigHandler); signal(SIGINT,SigHandler); while(!alsa_format->exiting) { memset(alsa_format->card_buffer,0,alsa_format->card_buffer_size); switch(alsa_format->format) { case SND_PCM_FORMAT_S16_LE: for(unsigned j=0;jcard][j]) { switch(alsa_output_channels[alsa_format->card][j]) { case 1: n=alsa_play_ring[alsa_format->card][j]-> read(alsa_buffer,alsa_format-> buffer_size/alsa_format->periods)/ (2*sizeof(int16_t)); stream_out_meter=0; // Stream Output Meters for(int k=0;kstream_out_meter) { stream_out_meter=abs(((int16_t *)alsa_buffer)[k]); } } alsa_stream_output_meter[alsa_format->card][j][0]-> addValue(((double)stream_out_meter)/32768.0); alsa_stream_output_meter[alsa_format->card][j][1]-> addValue(((double)stream_out_meter)/32768.0); modulo=alsa_format->channels; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { for(int k=0;k<(2*n);k++) { ((int16_t *)alsa_format->card_buffer)[modulo*k+2*i]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[k])); ((int16_t *)alsa_format->card_buffer)[modulo*k+2*i+1]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[k])); } } } n*=2; break; case 2: n=alsa_play_ring[alsa_format->card][j]-> read(alsa_buffer,alsa_format->buffer_size*2/ alsa_format->periods)/(2*sizeof(int16_t)); for(unsigned k=0;k<2;k++) { // Stream Output Meters stream_out_meter=0; for(int l=0;lstream_out_meter) { stream_out_meter=abs(((int16_t *)alsa_buffer)[l+k]); } } alsa_stream_output_meter[alsa_format->card][j][k]-> addValue(((double)stream_out_meter)/32768.0); } modulo=alsa_format->channels; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { for(int k=0;kcard_buffer)[modulo*k+2*i]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[2*k])); ((int16_t *)alsa_format->card_buffer)[modulo*k+2*i+1]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[2*k+1])); } } } break; } alsa_output_pos[alsa_format->card][j]+=n; if((n==0)&&alsa_eof[alsa_format->card][j]) { alsa_stopping[alsa_format->card][j]=true; } } } n=alsa_format->buffer_size/(2*alsa_format->periods); // // Process Passthroughs // for(unsigned i=0;icapture_channels;i+=2) { p=alsa_passthrough_ring[alsa_format->card][i/2]-> read(alsa_format->passthrough_buffer,4*n)/4; bool zero_volume = true; for (unsigned j=0;jchannels && zero_volume;j+=1) { zero_volume = (alsa_passthrough_volume[alsa_format->card][i/2][j] == 0.0); } if (!zero_volume) { for(unsigned j=0;jchannels;j+=2) { double passthrough_volume = alsa_passthrough_volume[alsa_format->card][i/2][j/2]; if (passthrough_volume != 0.0) { for(unsigned k=0;k<2;k++) { for(int l=0;l card_buffer)[alsa_format->channels*l+j+k]+= (int16_t)((double)((int16_t *)alsa_format->passthrough_buffer)[2*l+k]*passthrough_volume); } } } } } } // // Process Output Meters // for(unsigned i=0;ichannels;i+=2) { unsigned port=i/2; for(unsigned j=0;j<2;j++) { out_meter[port][j]=0; for(unsigned k=0;kbuffer_size;k++) { int16_t sample = ((int16_t *)alsa_format-> card_buffer)[alsa_format->channels*k+2*i+j]; if(sample> out_meter[i][j]) { out_meter[i][j]= sample; } } alsa_output_meter[alsa_format->card][i][j]-> addValue(((double)out_meter[i][j])/32768.0); } } break; case SND_PCM_FORMAT_S32_LE: for(unsigned j=0;jcard][j]) { switch(alsa_output_channels[alsa_format->card][j]) { case 1: n=alsa_play_ring[alsa_format->card][j]-> read(alsa_buffer,alsa_format->buffer_size/ alsa_format->periods)/(2*sizeof(int16_t)); stream_out_meter=0; for(int k=0;kstream_out_meter) { stream_out_meter=abs(((int16_t *)alsa_buffer)[k]); } } alsa_stream_output_meter[alsa_format->card][j][0]-> addValue(((double)stream_out_meter)/32768.0); alsa_stream_output_meter[alsa_format->card][j][1]-> addValue(((double)stream_out_meter)/32768.0); modulo=alsa_format->channels*2; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { for(int k=0;k<(2*n);k++) { ((int16_t *)alsa_format->card_buffer)[modulo*k+4*i+1]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[k])); ((int16_t *)alsa_format->card_buffer)[modulo*k+4*i+3]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[k])); } } } n*=2; break; case 2: n=alsa_play_ring[alsa_format->card][j]-> read(alsa_buffer,alsa_format->buffer_size*2/ alsa_format->periods)/(2*sizeof(int16_t)); for(unsigned k=0;k<2;k++) { // Stream Output Meters stream_out_meter=0; for(int l=0;lstream_out_meter) { stream_out_meter=abs(((int16_t *)alsa_buffer)[l+k]); } } alsa_stream_output_meter[alsa_format->card][j][k]-> addValue(((double)stream_out_meter)/32768.0); } modulo=alsa_format->channels*2; for(unsigned i=0;i<(alsa_format->channels/2);i++) { if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { for(int k=0;kcard_buffer)[modulo*k+4*i+1]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[2*k])); ((int16_t *)alsa_format->card_buffer)[modulo*k+4*i+3]+= (int16_t)(alsa_output_volume[alsa_format->card][i][j]* (double)(((int16_t *)alsa_buffer)[2*k+1])); } } } break; } alsa_output_pos[alsa_format->card][j]+=n; if((n==0)&&alsa_eof[alsa_format->card][j]) { alsa_stopping[alsa_format->card][j]=true; // Empty the ring buffer while(alsa_play_ring[alsa_format->card][j]-> read(alsa_buffer,alsa_format->buffer_size*2/ alsa_format->periods)/(2*sizeof(int16_t))>0); } } } n=alsa_format->buffer_size/(2*alsa_format->periods); // // Process Passthroughs // for(unsigned i=0;icapture_channels;i+=2) { p=alsa_passthrough_ring[alsa_format->card][i/2]-> read(alsa_format->passthrough_buffer,8*n)/8; bool zero_volume = true; for (unsigned j=0;jchannels && zero_volume;j+=1) { zero_volume = (alsa_passthrough_volume[alsa_format->card][i/2][j] == 0.0); } if (!zero_volume) { for(unsigned j=0;jchannels;j+=2) { double passthrough_volume = alsa_passthrough_volume[alsa_format->card][i/2][j/2]; if (passthrough_volume != 0.0) { for(unsigned k=0;k<2;k++) { for(int l=0;l card_buffer)[alsa_format->channels*l+j+k]+= (int32_t)((double)((int32_t *)alsa_format->passthrough_buffer)[2*l+k]*passthrough_volume); } } } } } } // // Process Output Meters // unsigned buffer_width; buffer_width = (alsa_format->buffer_size*2/alsa_format->periods); for(unsigned i=0;ichannels;i+=2) { unsigned port=i/2; for(unsigned j=0;j<2;j++) { out_meter[port][j]=0; for(unsigned k=0; k card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]; if (sample > out_meter[port][j]) { out_meter[port][j] = sample; } } alsa_output_meter[alsa_format->card][port][j]-> addValue(((double)out_meter[port][j])/32768.0); } } break; default: break; } int s=snd_pcm_writei(alsa_format->pcm,alsa_format->card_buffer,n); if(s!=n) { if(s<0) { RDApplication::syslog(rd_config,LOG_WARNING, "*** alsa error %d: %s",-s,snd_strerror(s)); } else { RDApplication::syslog(rd_config,LOG_WARNING, "period size mismatch - wrote %d",s); } } if((snd_pcm_state(alsa_format->pcm)!=SND_PCM_STATE_RUNNING)&& (!alsa_format->exiting)) { snd_pcm_drop (alsa_format->pcm); snd_pcm_prepare(alsa_format->pcm); RDApplication::syslog(rd_config,LOG_DEBUG, "****** ALSA Playout Xrun - Card: %d ******", alsa_format->card); } } return 0; } void MainObject::AlsaInitCallback() { int avg_periods= (330*system_sample_rate)/(1000*rd_config->alsaPeriodSize()); for(int i=0;ireset(); alsa_record_ring[i][j]=NULL; for(int k=0;k=alsa_fade_volume_db[card][stream]) { level=alsa_fade_volume_db[card][stream]; alsa_fade_timer[card][stream]->stop(); } } else { level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]- alsa_fade_increment[card][stream]; if(level<=alsa_fade_volume_db[card][stream]) { level=alsa_fade_volume_db[card][stream]; alsa_fade_timer[card][stream]->stop(); } } RDApplication::syslog(rd_config,LOG_DEBUG,"FadeLevel: %d",level); alsaSetOutputVolume(card,stream,alsa_fade_port[card][stream],level); #endif // ALSA } void MainObject::alsaRecordTimerData(int cardport) { #ifdef ALSA int card=cardport/RD_MAX_PORTS; int stream=cardport-card*RD_MAX_PORTS; alsaStopRecord(card,stream); stateRecordUpdate(card,stream,2); #endif // ALSA } void MainObject::alsaInit(RDStation *station) { #ifdef ALSA QString dev; int card=0; snd_pcm_t *pcm_play_handle; snd_pcm_t *pcm_capture_handle; snd_ctl_t *snd_ctl; snd_ctl_card_info_t *card_info=NULL; bool pcm_opened; // // Initialize Data Structures // for(int i=0;ichannels(); // // Stop & Fade Timers // QSignalMapper *stop_mapper=new QSignalMapper(this,"stop_mapper"); connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(alsaStopTimerData(int))); QSignalMapper *fade_mapper=new QSignalMapper(this,"fade_mapper"); connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(alsaFadeTimerData(int))); QSignalMapper *record_mapper=new QSignalMapper(this,"record_mapper"); connect(record_mapper,SIGNAL(mapped(int)), this,SLOT(alsaRecordTimerData(int))); for(int i=0;isetMapping(alsa_stop_timer[i][j],i*RD_MAX_STREAMS+j); connect(alsa_stop_timer[i][j],SIGNAL(timeout()),stop_mapper,SLOT(map())); alsa_fade_timer[i][j]=new QTimer(this); fade_mapper->setMapping(alsa_fade_timer[i][j],i*RD_MAX_STREAMS+j); connect(alsa_fade_timer[i][j],SIGNAL(timeout()),fade_mapper,SLOT(map())); } for(int j=0;jsetMapping(alsa_record_timer[i][j],i*RD_MAX_PORTS+j); connect(alsa_record_timer[i][j],SIGNAL(timeout()), record_mapper,SLOT(map())); } } // // Allocate Temporary Buffers // AlsaInitCallback(); alsa_wave_buffer=new int16_t[RINGBUFFER_SIZE]; alsa_wave24_buffer=new uint8_t[2*RINGBUFFER_SIZE]; //alsa_resample_buffer=new int16_t[2*RINGBUFFER_SIZE]; // // Start Up Interfaces // for(int i=0;isetCardDriver(i,RDStation::Alsa); if(snd_ctl_open(&snd_ctl,dev,0)<0) { RDApplication::syslog(rd_config,LOG_INFO, "no control device found for %s", (const char *)dev); station-> setCardName(i, QString().sprintf("ALSA Device %s",(const char *)dev)); } else { snd_ctl_card_info_malloc(&card_info); snd_ctl_card_info(snd_ctl,card_info); station-> setCardName(i,snd_ctl_card_info_get_longname(card_info)); snd_ctl_close(snd_ctl); } station-> setCardInputs(i, alsa_capture_format[i].channels/RD_DEFAULT_CHANNELS); station-> setCardOutputs(i,alsa_play_format[i].channels/RD_DEFAULT_CHANNELS); } else { i--; } card++; if(!pcm_opened) { return; } } } #endif // ALSA } void MainObject::alsaFree() { #ifdef ALSA for(int i=0;iopenWave()) { RDApplication::syslog(rd_config,LOG_DEBUG, "alsaLoadPlayback(%s) openWave() failed to open file", (const char *)wavename.toUtf8()); delete alsa_play_wave[card][*stream]; alsa_play_wave[card][*stream]=NULL; FreeAlsaOutputStream(card,*stream); *stream=-1; return false; } switch(alsa_play_wave[card][*stream]->getFormatTag()) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_VORBIS: break; case WAVE_FORMAT_MPEG: InitMadDecoder(card,*stream,alsa_play_wave[card][*stream]); break; default: RDApplication::syslog(rd_config,LOG_WARNING, "alsaLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed", (const char *)wavename.toUtf8(), alsa_play_wave[card][*stream]->getFormatTag(), alsa_play_wave[card][*stream]->getBitsPerSample()); delete alsa_play_wave[card][*stream]; alsa_play_wave[card][*stream]=NULL; FreeAlsaOutputStream(card,*stream); *stream=-1; return false; } alsa_output_channels[card][*stream]= alsa_play_wave[card][*stream]->getChannels(); alsa_stopping[card][*stream]=false; alsa_offset[card][*stream]=0; alsa_output_pos[card][*stream]=0; alsa_eof[card][*stream]=false; alsa_play_ring[card][*stream]->reset(); FillAlsaOutputStream(card,*stream); return true; #else return false; #endif // ALSA } bool MainObject::alsaUnloadPlayback(int card,int stream) { #ifdef ALSA if(alsa_play_ring[card][stream]==NULL) { return false; } alsa_playing[card][stream]=false; switch(alsa_play_wave[card][stream]->getFormatTag()) { case WAVE_FORMAT_MPEG: FreeMadDecoder(card,stream); break; } alsa_play_wave[card][stream]->closeWave(); delete alsa_play_wave[card][stream]; alsa_play_wave[card][stream]=NULL; FreeAlsaOutputStream(card,stream); return true; #else return false; #endif // ALSA } bool MainObject::alsaPlaybackPosition(int card,int stream,unsigned pos) { #ifdef ALSA unsigned offset=0; if(alsa_play_format[card].exiting){ return false; } switch(alsa_play_wave[card][stream]->getFormatTag()) { case WAVE_FORMAT_PCM: offset=(unsigned)((double)alsa_play_wave[card][stream]->getSamplesPerSec()* (double)alsa_play_wave[card][stream]->getBlockAlign()* (double)pos/1000); alsa_offset[card][stream]= offset/alsa_play_wave[card][stream]->getBlockAlign(); offset= alsa_offset[card][stream]*alsa_play_wave[card][stream]->getBlockAlign(); break; case WAVE_FORMAT_MPEG: offset=(unsigned)((double)alsa_play_wave[card][stream]->getSamplesPerSec()* (double)pos/1000); alsa_offset[card][stream]=offset/1152*1152; offset=alsa_offset[card][stream]/1152* alsa_play_wave[card][stream]->getBlockAlign(); FreeMadDecoder(card,stream); InitMadDecoder(card,stream,alsa_play_wave[card][stream]); break; } if(alsa_offset[card][stream]> (int)alsa_play_wave[card][stream]->getSampleLength()) { return false; } alsa_output_pos[card][stream]=0; alsa_play_wave[card][stream]->seekWave(offset,SEEK_SET); alsa_eof[card][stream]=false; alsa_play_ring[card][stream]->reset(); FillAlsaOutputStream(card,stream); if(alsa_playing[card][stream]) { alsa_stop_timer[card][stream]->stop(); alsa_stop_timer[card][stream]-> start(alsa_play_wave[card][stream]->getExtTimeLength()-pos,true); } return true; #else return false; #endif // ALSA } bool MainObject::alsaPlay(int card,int stream,int length,int speed,bool pitch, bool rates) { #ifdef ALSA if((alsa_play_ring[card][stream]==NULL)|| alsa_playing[card][stream]||(speed!=RD_TIMESCALE_DIVISOR)) { return false; } alsa_playing[card][stream]=true; if(length>0) { alsa_stop_timer[card][stream]->start(length,true); } statePlayUpdate(card,stream,1); return true; #else return false; #endif // ALSA } bool MainObject::alsaTimescaleSupported(int card) { #ifdef ALSA return false; #else return false; #endif // ALSA } bool MainObject::alsaStopPlayback(int card,int stream) { #ifdef ALSA if((alsa_play_ring[card][stream]==NULL)||(!alsa_playing[card][stream])) { return false; } alsa_playing[card][stream]=false; alsa_play_ring[card][stream]->reset(); alsa_stop_timer[card][stream]->stop(); statePlayUpdate(card,stream,2); return true; #else return false; #endif // ALSA } bool MainObject::alsaLoadRecord(int card,int stream,int coding,int chans, int samprate,int bitrate,QString wavename) { #ifdef ALSA alsa_record_wave[card][stream]=new RDWaveFile(wavename); switch(coding) { case 0: // PCM16 alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_PCM); alsa_record_wave[card][stream]->setChannels(chans); alsa_record_wave[card][stream]->setSamplesPerSec(samprate); alsa_record_wave[card][stream]->setBitsPerSample(16); break; case 4: // PCM24 alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_PCM); alsa_record_wave[card][stream]->setChannels(chans); alsa_record_wave[card][stream]->setSamplesPerSec(samprate); alsa_record_wave[card][stream]->setBitsPerSample(24); break; case 2: // MPEG Layer 2 if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) { delete alsa_record_wave[card][stream]; alsa_record_wave[card][stream]=NULL; return false; } alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_MPEG); alsa_record_wave[card][stream]->setChannels(chans); alsa_record_wave[card][stream]->setSamplesPerSec(samprate); alsa_record_wave[card][stream]->setBitsPerSample(16); alsa_record_wave[card][stream]->setHeadLayer(ACM_MPEG_LAYER2); switch(chans) { case 1: alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL); break; case 2: alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_STEREO); break; default: RDApplication::syslog(rd_config,LOG_WARNING, "requested unsupported channel count %d, card: %d, stream: %d", chans,card,stream); delete alsa_record_wave[card][stream]; alsa_record_wave[card][stream]=NULL; return false; } alsa_record_wave[card][stream]->setHeadBitRate(bitrate); alsa_record_wave[card][stream]->setMextChunk(true); alsa_record_wave[card][stream]->setMextHomogenous(true); alsa_record_wave[card][stream]->setMextPaddingUsed(false); alsa_record_wave[card][stream]->setMextHackedBitRate(true); alsa_record_wave[card][stream]->setMextFreeFormat(false); alsa_record_wave[card][stream]-> setMextFrameSize(144*alsa_record_wave[card][stream]->getHeadBitRate()/ alsa_record_wave[card][stream]->getSamplesPerSec()); alsa_record_wave[card][stream]->setMextAncillaryLength(5); alsa_record_wave[card][stream]->setMextLeftEnergyPresent(true); if(chans>1) { alsa_record_wave[card][stream]->setMextRightEnergyPresent(true); } else { alsa_record_wave[card][stream]->setMextRightEnergyPresent(false); } alsa_record_wave[card][stream]->setMextPrivateDataPresent(false); break; default: RDApplication::syslog(rd_config,LOG_WARNING, "requested invalid audio encoding %d, card: %d, stream: %d", coding,card,stream); delete alsa_record_wave[card][stream]; alsa_record_wave[card][stream]=NULL; return false; } alsa_record_wave[card][stream]->setBextChunk(true); alsa_record_wave[card][stream]->setLevlChunk(true); if(!alsa_record_wave[card][stream]->createWave()) { delete alsa_record_wave[card][stream]; alsa_record_wave[card][stream]=NULL; return false; } chown((const char *)wavename,rd_config->uid(),rd_config->gid()); alsa_input_channels[card][stream]=chans; alsa_record_ring[card][stream]=new RDRingBuffer(RINGBUFFER_SIZE); alsa_record_ring[card][stream]->reset(); alsa_ready[card][stream]=true; return true; #else return false; #endif // ALSA } bool MainObject::alsaUnloadRecord(int card,int stream,unsigned *len) { #ifdef ALSA alsa_recording[card][stream]=false; alsa_ready[card][stream]=false; EmptyAlsaInputStream(card,stream); *len=alsa_samples_recorded[card][stream]; alsa_samples_recorded[card][stream]=0; alsa_record_wave[card][stream]->closeWave(*len); delete alsa_record_wave[card][stream]; alsa_record_wave[card][stream]=NULL; delete alsa_record_ring[card][stream]; alsa_record_ring[card][stream]=NULL; FreeTwoLameEncoder(card,stream); return true; #else return false; #endif // ALSA } bool MainObject::alsaRecord(int card,int stream,int length,int thres) { #ifdef ALSA if(!alsa_ready[card][stream]) { return false; } alsa_recording[card][stream]=true; if(alsa_input_vox[card][stream]==0.0) { if(length>0) { alsa_record_timer[card][stream]->start(length,true); } stateRecordUpdate(card,stream,4); } return true; #else return false; #endif // ALSA } bool MainObject::alsaStopRecord(int card,int stream) { #ifdef ALSA if(!alsa_recording[card][stream]) { return false; } alsa_recording[card][stream]=false; return true; #else return false; #endif // ALSA } bool MainObject::alsaSetInputVolume(int card,int stream,int level) { #ifdef ALSA if(level>-10000) { alsa_input_volume[card][stream]=pow(10.0,(double)level/2000.0); alsa_input_volume_db[card][stream]=level; } else { alsa_input_volume[card][stream]=0.0; alsa_input_volume_db[card][stream]=-10000; } return true; #else return false; #endif // ALSA } bool MainObject::alsaSetOutputVolume(int card,int stream,int port,int level) { #ifdef ALSA if(level>-10000) { alsa_output_volume[card][port][stream]=pow(10.0,(double)level/2000.0); alsa_output_volume_db[card][port][stream]=level; } else { alsa_output_volume[card][port][stream]=0.0; alsa_output_volume_db[card][port][stream]=-10000; } return true; #else return false; #endif // ALSA } bool MainObject::alsaFadeOutputVolume(int card,int stream,int port,int level, int length) { #ifdef ALSA int diff; if(alsa_fade_timer[card][stream]->isActive()) { alsa_fade_timer[card][stream]->stop(); } if(level>alsa_output_volume_db[card][port][stream]) { alsa_fade_up[card][stream]=true; diff=level-alsa_output_volume_db[card][port][stream]; } else { alsa_fade_up[card][stream]=false; diff=alsa_output_volume_db[card][port][stream]-level; } alsa_fade_volume_db[card][stream]=level; alsa_fade_port[card][stream]=port; alsa_fade_increment[card][stream]=diff*RD_ALSA_FADE_INTERVAL/length; alsa_fade_timer[card][stream]->start(RD_ALSA_FADE_INTERVAL); return true; #else return false; #endif // ALSA } bool MainObject::alsaSetInputLevel(int card,int port,int level) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaSetOutputLevel(int card,int port,int level) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaSetInputMode(int card,int stream,int mode) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaSetOutputMode(int card,int stream,int mode) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaSetInputVoxLevel(int card,int stream,int level) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaSetInputType(int card,int port,int type) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaGetInputStatus(int card,int port) { #ifdef ALSA return true; #else return false; #endif // ALSA } bool MainObject::alsaGetInputMeters(int card,int port,int16_t levels[2]) { #ifdef ALSA double meter; for(int i=0;i<2;i++) { meter=alsa_input_meter[card][port][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(int16_t)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // ALSA } bool MainObject::alsaGetOutputMeters(int card,int port,int16_t levels[2]) { #ifdef ALSA double meter; for(int i=0;i<2;i++) { meter=alsa_output_meter[card][port][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(int16_t)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // ALSA } bool MainObject::alsaGetStreamOutputMeters(int card,int stream,int16_t levels[2]) { #ifdef ALSA double meter; for(int i=0;i<2;i++) { meter=alsa_stream_output_meter[card][stream][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(int16_t)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // ALSA } void MainObject::alsaGetOutputPosition(int card,unsigned *pos) {// pos is in miliseconds #ifdef ALSA for(int i=0;igetSamplesPerSec(); } else { pos[i]=0; } } #endif // ALSA } bool MainObject::alsaSetPassthroughLevel(int card,int in_port,int out_port, int level) { #ifdef ALSA if(level>-10000) { alsa_passthrough_volume[card][in_port][out_port]= pow(10.0,(double)level/2000.0); alsa_passthrough_volume_db[card][in_port][out_port]=level; } else { alsa_passthrough_volume[card][in_port][out_port]=0.0; alsa_passthrough_volume_db[card][in_port][out_port]=-10000; } return true; #else return false; #endif // ALSA } #ifdef ALSA bool MainObject::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; int dir; int err; pthread_attr_t pthread_attr; unsigned sr; memset(&alsa_capture_format[card],0,sizeof(struct alsa_format)); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_any(pcm,hwparams); RDApplication::syslog(rd_config,LOG_INFO,"Starting ALSA Capture Device %s:", (const char *)dev.toUtf8()); // // Access Type // if(snd_pcm_hw_params_test_access(pcm,hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)<0) { RDApplication::syslog(rd_config,LOG_WARNING, " Interleaved access not supported,"); RDApplication::syslog(rd_config,LOG_WARNING, " aborting initialization of device."); return false; } snd_pcm_hw_params_set_access(pcm,hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); // // Sample Format // if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S32_LE)==0) { alsa_capture_format[card].format=SND_PCM_FORMAT_S32_LE; RDApplication::syslog(rd_config,LOG_INFO," Format = 32 bit little-endian"); } else { if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S16_LE)==0) { alsa_capture_format[card].format=SND_PCM_FORMAT_S16_LE; RDApplication::syslog(rd_config,LOG_INFO, " Format = 16 bit little-endian"); } else { RDApplication::syslog(rd_config,LOG_WARNING, " Neither 16 nor 32 bit little-endian formats available,"); RDApplication::syslog(rd_config,LOG_WARNING, " aborting initialization of device."); return false; } } snd_pcm_hw_params_set_format(pcm,hwparams,alsa_capture_format[card].format); // // Sample Rate // if(alsa_play_format[card].sample_rate>0) { sr=alsa_play_format[card].sample_rate; } else { sr=system_sample_rate; } snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir); if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))|| (sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) { RDApplication::syslog(rd_config,LOG_WARNING, " Asked for sample rate %u, got %u", system_sample_rate,sr); RDApplication::syslog(rd_config,LOG_WARNING, " Sample rate unsupported by device"); return false; } alsa_capture_format[card].sample_rate=sr; RDApplication::syslog(rd_config,LOG_INFO," SampleRate = %u",sr); // // Channels // if(rd_config->alsaChannelsPerPcm()<0) { alsa_capture_format[card].channels=RD_DEFAULT_CHANNELS*RD_MAX_PORTS; } else { alsa_capture_format[card].channels=rd_config->alsaChannelsPerPcm(); } snd_pcm_hw_params_set_channels_near(pcm,hwparams, &alsa_capture_format[card].channels); alsa_play_format[card].capture_channels=alsa_capture_format[card].channels; RDApplication::syslog(rd_config,LOG_INFO," Aggregate Channels = %u", alsa_capture_format[card].channels); // // Buffer Size // alsa_capture_format[card].periods=rd_config->alsaPeriodQuantity(); snd_pcm_hw_params_set_periods_near(pcm,hwparams, &alsa_capture_format[card].periods,&dir); RDApplication::syslog(rd_config,LOG_INFO, " Periods = %u",alsa_capture_format[card].periods); alsa_capture_format[card].buffer_size= alsa_capture_format[card].periods*rd_config->alsaPeriodSize(); snd_pcm_hw_params_set_buffer_size_near(pcm,hwparams, &alsa_capture_format[card].buffer_size); RDApplication::syslog(rd_config,LOG_INFO," BufferSize = %u frames", (unsigned)alsa_capture_format[card].buffer_size); // // Fire It Up // if((err=snd_pcm_hw_params(pcm,hwparams))<0) { RDApplication::syslog(rd_config,LOG_WARNING, " Device Error: %s,",snd_strerror(err)); RDApplication::syslog(rd_config,LOG_WARNING, " aborting initialization of device."); return false; } RDApplication::syslog(rd_config,LOG_INFO," Device started successfully"); switch(alsa_capture_format[card].format) { case SND_PCM_FORMAT_S16_LE: alsa_capture_format[card].card_buffer_size= alsa_capture_format[card].buffer_size* alsa_capture_format[card].channels*2; break; case SND_PCM_FORMAT_S32_LE: alsa_capture_format[card].card_buffer_size= alsa_capture_format[card].buffer_size* alsa_capture_format[card].channels*4; break; default: break; } alsa_capture_format[card].card_buffer= new char[alsa_capture_format[card].card_buffer_size]; alsa_capture_format[card].passthrough_buffer= new char[alsa_capture_format[card].card_buffer_size]; alsa_capture_format[card].pcm=pcm; alsa_capture_format[card].card=card; // // Set Wake-up Timing // snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(pcm,swparams); snd_pcm_sw_params_set_avail_min(pcm,swparams,rd_config->alsaPeriodSize()); if((err=snd_pcm_sw_params(pcm,swparams))<0) { RDApplication::syslog(rd_config,LOG_WARNING, "ALSA Device %s: %s",(const char *)dev.toUtf8(), snd_strerror(err)); return false; } // // Start the Callback // pthread_attr_init(&pthread_attr); /* if(use_realtime) { pthread_attr_setschedpolicy(&pthread_attr,SCHED_FIFO); } */ alsa_capture_format[card].exiting = false; pthread_create(&alsa_capture_format[card].thread,&pthread_attr, AlsaCaptureCallback,&alsa_capture_format[card]); return true; } bool MainObject::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm) { snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; int dir; int err; pthread_attr_t pthread_attr; unsigned sr; memset(&alsa_play_format[card],0,sizeof(struct alsa_format)); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_any(pcm,hwparams); RDApplication::syslog(rd_config,LOG_INFO,"Starting ALSA Play Device %s:", (const char *)dev.toUtf8()); // // Access Type // if(snd_pcm_hw_params_test_access(pcm,hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)<0) { RDApplication::syslog(rd_config,LOG_WARNING, " Interleaved access not supported,"); RDApplication::syslog(rd_config,LOG_WARNING, " aborting initialization of device."); return false; } snd_pcm_hw_params_set_access(pcm,hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); // // Sample Format // if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S32_LE)==0) { alsa_play_format[card].format=SND_PCM_FORMAT_S32_LE; RDApplication::syslog(rd_config,LOG_INFO," Format = 32 bit little-endian"); } else { if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S16_LE)==0) { alsa_play_format[card].format=SND_PCM_FORMAT_S16_LE; RDApplication::syslog(rd_config,LOG_INFO, " Format = 16 bit little-endian"); } else { RDApplication::syslog(rd_config,LOG_WARNING, " Neither 16 nor 32 bit little-endian formats available,"); RDApplication::syslog(rd_config,LOG_WARNING, " aborting initialization of device."); return false; } } snd_pcm_hw_params_set_format(pcm,hwparams,alsa_play_format[card].format); // // Sample Rate // sr=system_sample_rate; snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir); if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))|| (sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) { RDApplication::syslog(rd_config,LOG_WARNING, " Asked for sample rate %u, got %u", system_sample_rate,sr); RDApplication::syslog(rd_config,LOG_WARNING, " Sample rate unsupported by device"); return false; } alsa_play_format[card].sample_rate=sr; RDApplication::syslog(rd_config,LOG_INFO," SampleRate = %u",sr); // // Channels // if(rd_config->alsaChannelsPerPcm()<0) { alsa_play_format[card].channels=RD_DEFAULT_CHANNELS*RD_MAX_PORTS; } else { alsa_play_format[card].channels=rd_config->alsaChannelsPerPcm(); } snd_pcm_hw_params_set_channels_near(pcm,hwparams, &alsa_play_format[card].channels); RDApplication::syslog(rd_config,LOG_INFO," Aggregate Channels = %u", alsa_play_format[card].channels); // // Buffer Size // alsa_play_format[card].periods=rd_config->alsaPeriodQuantity(); snd_pcm_hw_params_set_periods_near(pcm,hwparams, &alsa_play_format[card].periods,&dir); RDApplication::syslog(rd_config,LOG_INFO, " Periods = %u",alsa_play_format[card].periods); alsa_play_format[card].buffer_size= alsa_play_format[card].periods*rd_config->alsaPeriodSize(); snd_pcm_hw_params_set_buffer_size_near(pcm,hwparams, &alsa_play_format[card].buffer_size); RDApplication::syslog(rd_config,LOG_INFO," BufferSize = %u frames", (unsigned)alsa_play_format[card].buffer_size); // // Fire It Up // if((err=snd_pcm_hw_params(pcm,hwparams))<0) { RDApplication::syslog(rd_config,LOG_WARNING, " Device Error: %s,",snd_strerror(err)); RDApplication::syslog(rd_config,LOG_ERR, " aborting initialization of device."); return false; } RDApplication::syslog(rd_config,LOG_INFO," Device started successfully"); switch(alsa_play_format[card].format) { case SND_PCM_FORMAT_S16_LE: alsa_play_format[card].card_buffer_size= alsa_play_format[card].buffer_size*alsa_play_format[card].channels*2; break; case SND_PCM_FORMAT_S32_LE: alsa_play_format[card].card_buffer_size= alsa_play_format[card].buffer_size*alsa_play_format[card].channels*4; break; default: break; } alsa_play_format[card].card_buffer= new char[alsa_play_format[card].card_buffer_size]; alsa_play_format[card].passthrough_buffer= new char[alsa_play_format[card].card_buffer_size]; alsa_play_format[card].pcm=pcm; alsa_play_format[card].card=card; // // Set Wake-up Timing // snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(pcm,swparams); snd_pcm_sw_params_set_avail_min(pcm,swparams,rd_config->alsaPeriodSize()); if((err=snd_pcm_sw_params(pcm,swparams))<0) { RDApplication::syslog(rd_config,LOG_WARNING,"ALSA Device %s: %s", (const char *)dev.toUtf8(),snd_strerror(err)); return false; } // // Start the Callback // pthread_attr_init(&pthread_attr); /* if(use_realtime) { pthread_attr_setschedpolicy(&pthread_attr,SCHED_FIFO); } */ alsa_play_format[card].exiting = false; pthread_create(&alsa_play_format[card].thread,&pthread_attr, AlsaPlayCallback,&alsa_play_format[card]); return true; } int MainObject::GetAlsaOutputStream(int card) { for(int i=0;i read((char *)alsa_wave_buffer,alsa_record_ring[card][stream]-> readSpace()); WriteAlsaBuffer(card,stream,alsa_wave_buffer,n); } void MainObject::WriteAlsaBuffer(int card,int stream,int16_t *buffer,unsigned len) { ssize_t s; unsigned char mpeg[2048]; unsigned frames; unsigned n; frames=len/(2*alsa_record_wave[card][stream]->getChannels()); alsa_samples_recorded[card][stream]+=frames; switch(alsa_record_wave[card][stream]->getFormatTag()) { case WAVE_FORMAT_PCM: switch(alsa_record_wave[card][stream]->getBitsPerSample()) { case 16: // PCM16 alsa_record_wave[card][stream]->writeWave(buffer,len); break; case 24: // PCM24 for(unsigned i=0;i<(len/2);i++) { alsa_wave24_buffer[3*i]=0; // FIXME: we lose eight bits here! alsa_wave24_buffer[3*i+1]=((uint8_t *)buffer)[2*i]; alsa_wave24_buffer[3*i+2]=((uint8_t *)buffer)[2*i+1]; } alsa_record_wave[card][stream]->writeWave(alsa_wave24_buffer,3*len/2); break; } break; case WAVE_FORMAT_MPEG: #ifdef HAVE_TWOLAME for(unsigned i=0;iframes) { n=frames-i; } else { n=1152; } if((s=twolame_encode_buffer_interleaved(twolame_lameopts[card][stream], buffer+i*alsa_record_wave[card][stream]->getChannels(), n,mpeg,2048))>=0) { alsa_record_wave[card][stream]->writeWave(mpeg,s); } else { RDApplication::syslog(rd_config,LOG_WARNING, "TwoLAME encode error, card: %d, stream: %d", card,stream); } } #endif // HAVE_TWOLAME break; } } void MainObject::FillAlsaOutputStream(int card,int stream) { unsigned mpeg_frames=0; unsigned frame_offset=0; int m=0; int n=0; double ratio=0.0; int free=(alsa_play_ring[card][stream]->writeSpace()-1); if(free<=0) { return; } ratio=(double)alsa_play_format[card].sample_rate/ (double)alsa_play_wave[card][stream]->getSamplesPerSec(); switch(alsa_play_wave[card][stream]->getFormatTag()) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_VORBIS: switch(alsa_play_wave[card][stream]->getBitsPerSample()) { case 16: // PCM16 free=(int)((double)free/ratio)/(2*alsa_output_channels[card][stream])* (2*alsa_output_channels[card][stream]); n=alsa_play_wave[card][stream]->readWave(alsa_wave_buffer,free); if(n!=free) { alsa_eof[card][stream]=true; alsa_stop_timer[card][stream]->stop(); } break; case 24: // PCM24 free=(int)((double)free/ratio)/(2*alsa_output_channels[card][stream])* (2*alsa_output_channels[card][stream]); n=2*alsa_play_wave[card][stream]->readWave(alsa_wave24_buffer,3*free/2)/3; if(n!=free) { alsa_eof[card][stream]=true; alsa_stop_timer[card][stream]->stop(); break; } for(int i=0;i readWave(mad_mpeg[card][stream]+mad_left_over[card][stream], mad_frame_size[card][stream]); if(m==mad_frame_size[card][stream]) { mad_stream_buffer(&mad_stream[card][stream],mad_mpeg[card][stream], m+mad_left_over[card][stream]); while(mad_frame_decode(&mad_frame[card][stream], &mad_stream[card][stream])==0) { mad_synth_frame(&mad_synth[card][stream],&mad_frame[card][stream]); n+=(2*alsa_output_channels[card][stream]* mad_synth[card][stream].pcm.length); for(int j=0;jstop(); continue; } mad_left_over[card][stream]= mad_stream[card][stream].bufend-mad_stream[card][stream].next_frame; memmove(mad_mpeg[card][stream],mad_stream[card][stream].next_frame, mad_left_over[card][stream]); } #endif // HAVE_MAD break; } alsa_play_ring[card][stream]->write((char *)alsa_wave_buffer,n); } #endif // ALSA void MainObject::AlsaClock() { #ifdef ALSA for(int i=0;i