// cae_jack.cpp // // The JACK 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 #include #include #include #ifdef JACK // // Callback Variables // jack_client_t *jack_client; RDMeterAverage *jack_input_meter[RD_MAX_PORTS][2]; RDMeterAverage *jack_output_meter[RD_MAX_PORTS][2]; RDMeterAverage *jack_stream_output_meter[RD_MAX_STREAMS][2]; volatile jack_default_audio_sample_t jack_input_volume[RD_MAX_PORTS]; volatile jack_default_audio_sample_t jack_output_volume[RD_MAX_PORTS][RD_MAX_STREAMS]; volatile jack_default_audio_sample_t jack_passthrough_volume[RD_MAX_PORTS][RD_MAX_PORTS]; volatile jack_default_audio_sample_t jack_input_vox[RD_MAX_PORTS]; jack_port_t *jack_input_port[RD_MAX_PORTS][2]; jack_port_t *jack_output_port[RD_MAX_PORTS][2]; volatile int jack_input_channels[RD_MAX_PORTS]; volatile int jack_output_channels[RD_MAX_STREAMS]; volatile jack_default_audio_sample_t *jack_input_buffer[RD_MAX_PORTS][2]; volatile jack_default_audio_sample_t *jack_output_buffer[RD_MAX_PORTS][2]; RDRingBuffer *jack_play_ring[RD_MAX_STREAMS]; RDRingBuffer *jack_record_ring[RD_MAX_PORTS]; volatile bool jack_playing[RD_MAX_STREAMS]; volatile bool jack_stopping[RD_MAX_STREAMS]; volatile bool jack_eof[RD_MAX_STREAMS]; volatile bool jack_recording[RD_MAX_PORTS]; volatile bool jack_ready[RD_MAX_PORTS]; volatile int jack_output_pos[RD_MAX_STREAMS]; volatile unsigned jack_output_sample_rate[RD_MAX_STREAMS]; volatile unsigned jack_sample_rate; int jack_input_mode[RD_MAX_CARDS][RD_MAX_PORTS]; int jack_card_process; // local copy of object member jack_card, for use by the callback process. // // Callback Buffers // jack_default_audio_sample_t jack_callback_buffer[RINGBUFFER_SIZE]; int JackProcess(jack_nframes_t nframes, void *arg) { unsigned n=0; jack_default_audio_sample_t in_meter[2]; jack_default_audio_sample_t out_meter[2]; jack_default_audio_sample_t stream_out_meter; // // Ensure Buffers are Valid // for(int i=0;i0.0) { for(int k=0;k<2;k++) { if((jack_output_port[j][k]!=NULL)&&(jack_input_port[i][k]!=NULL)) { for(unsigned l=0;l write((char *)jack_callback_buffer, nframes*sizeof(jack_default_audio_sample_t))/ sizeof(jack_default_audio_sample_t); break; case 2: // stereo for(unsigned j=0;j write((char *)jack_callback_buffer, 2*nframes*sizeof(jack_default_audio_sample_t))/ (2*sizeof(jack_default_audio_sample_t)); break; } } } } // // Process Output Streams // for(int i=0;i read((char *)jack_callback_buffer, nframes*sizeof(jack_default_audio_sample_t))/ sizeof(jack_default_audio_sample_t); stream_out_meter=0.0; for(unsigned j=0;jstream_out_meter) { stream_out_meter=fabsf(jack_callback_buffer[j]); } } jack_stream_output_meter[i][0]->addValue(stream_out_meter); jack_stream_output_meter[i][1]->addValue(stream_out_meter); break; case 2: n=jack_play_ring[i]-> read((char *)jack_callback_buffer, 2*nframes*sizeof(jack_default_audio_sample_t))/ (2*sizeof(jack_default_audio_sample_t)); for(unsigned j=0;j<2;j++) { // Stream Output Meters stream_out_meter=0.0; for(unsigned k=0;kstream_out_meter) { stream_out_meter=fabsf(jack_callback_buffer[k+j]); } } jack_stream_output_meter[i][j]->addValue(stream_out_meter); } break; } for(int j=0;j0.0) { switch(jack_output_channels[i]) { case 1: for(unsigned k=0;kin_meter[1]) in_meter[1]=jack_input_buffer[i][1][k]; break; case 2: // L only if(jack_input_buffer[i][0][k]>in_meter[0]) in_meter[0]=jack_input_buffer[i][0][k]; break; case 1: // swap if(jack_input_buffer[i][0][k]>in_meter[1]) in_meter[1]=jack_input_buffer[i][0][k]; if(jack_input_buffer[i][1][k]>in_meter[0]) in_meter[0]=jack_input_buffer[i][1][k]; break; case 0: // normal default: if(jack_input_buffer[i][0][k]>in_meter[0]) in_meter[0]=jack_input_buffer[i][0][k]; if(jack_input_buffer[i][1][k]>in_meter[1]) in_meter[1]=jack_input_buffer[i][1][k]; break; } } // for nframes jack_input_meter[i][0]->addValue(in_meter[0]); jack_input_meter[i][1]->addValue(in_meter[1]); } if(jack_output_port[i][0]!=NULL) { // output meters for(int j=0;j<2;j++) { out_meter[j]=0.0; for(unsigned k=0;kout_meter[j]) out_meter[j]=jack_output_buffer[i][j][k]; } jack_output_meter[i][j]->addValue(out_meter[j]); } } } // for RD_MAX_PORTS return 0; } int JackSampleRate(jack_nframes_t nframes, void *arg) { jack_sample_rate=nframes; return 0; } void JackError(const char *desc) { fprintf(stderr,"caed: Jack error: %s\n",desc); } void JackShutdown(void *arg) { } void JackInitCallback() { int avg_periods=(int)(330.0*jack_get_sample_rate(jack_client)/ (1000.0*jack_get_buffer_size(jack_client))); for(int i=0;istop(); } } else { level=jack_output_volume_db[jack_fade_port[stream]][stream]+ jack_fade_increment[stream]; if(level>=jack_fade_volume_db[stream]) { level=jack_fade_volume_db[stream]; jack_fade_timer[stream]->stop(); } } jackSetOutputVolume(jack_card,stream,jack_fade_port[stream],level); #endif // JACK } void MainObject::jackRecordTimerData(int stream) { #ifdef JACK jackStopRecord(jack_card,stream); stateRecordUpdate(jack_card,stream,2); #endif // JACK } void MainObject::jackClientStartData() { #ifdef JACK QString sql=QString("select ")+ "DESCRIPTION,"+ // 00 "COMMAND_LINE "+ // 01 "from JACK_CLIENTS where "+ "STATION_NAME=\""+RDEscapeString(rd_config->stationName())+"\""; RDSqlQuery *q=new RDSqlQuery(sql); while(q->next()) { QString cmd=RDDateDecode(q->value(1).toString(),QDate::currentDate(), cae_station,rd_config, rd_config->provisioningServiceName(rd_config->stationName())); QStringList args=cmd.split(" ",QString::SkipEmptyParts); QString program=args.at(0); args.removeFirst(); jack_clients.push_back(new QProcess(this)); jack_clients.back()->start(program,args); if(jack_clients.back()->waitForStarted()) { RDApplication::syslog(rd_config,LOG_INFO,"started JACK Client \"%s\"", (const char *)q->value(0).toString().toUtf8()); } else { RDApplication::syslog(rd_config,LOG_WARNING, "failed to start JACK Client \"%s\" [%s]", (const char *)q->value(0).toString().toUtf8(), (const char *)q->value(1).toString().toUtf8()); } sleep(1); } delete q; #endif // JACK } void MainObject::jackInit(RDStation *station) { #ifdef JACK jack_options_t jackopts=JackNullOption; jack_status_t jackstat=JackFailure; jack_connected=false; jack_activated=false; // // Get Next Available Card Number // for(jack_card=0;jack_cardstartJack()) { QStringList args= station->jackCommandLine().split(" ",QString::SkipEmptyParts); if(args.size()) { QString program=args.at(0); args.removeFirst(); QProcess *proc=new QProcess(this); proc->start(program,args); if(proc->waitForStarted()) { RDApplication::syslog(rd_config,LOG_INFO,"JACK server started"); } else { RDApplication::syslog(rd_config,LOG_WARNING, "failed to start JACK server"); } sleep(1); } else { RDApplication::syslog(rd_config,LOG_WARNING, "could not start JACK server: no command line specified"); } } // // Attempt to Connect to Jack Server // jackopts=JackNoStartServer; if(station->jackServerName().isEmpty()) { jack_client=jack_client_open(name,jackopts,&jackstat); } else { jack_client=jack_client_open(name,jackopts,&jackstat, (const char *)station->jackServerName()); } if(jack_client==NULL) { if((jackstat&JackInvalidOption)!=0) { fprintf (stderr, "invalid or unsupported JACK option\n"); RDApplication::syslog(rd_config,LOG_WARNING, "invalid or unsupported JACK option"); } if((jackstat&JackServerError)!=0) { fprintf (stderr, "communication error with the JACK server\n"); RDApplication::syslog(rd_config,LOG_WARNING, "communication error with the JACK server"); } if((jackstat&JackNoSuchClient)!=0) { fprintf (stderr, "requested JACK client does not exist\n"); RDApplication::syslog(rd_config,LOG_WARNING, "requested JACK client does not exist"); } if((jackstat&JackLoadFailure)!=0) { fprintf (stderr, "unable to load internal JACK client\n"); RDApplication::syslog(rd_config,LOG_WARNING, "unable to load internal JACK client"); } if((jackstat&JackInitFailure)!=0) { fprintf (stderr, "unable to initialize JACK client\n"); RDApplication::syslog(rd_config,LOG_WARNING, "unable to initialize JACK client"); } if((jackstat&JackShmFailure)!=0) { fprintf (stderr, "unable to access JACK shared memory\n"); RDApplication::syslog(rd_config,LOG_WARNING, "unable to access JACK shared memory"); } if((jackstat&JackVersionError)!=0) { fprintf (stderr, "JACK protocol version mismatch\n"); RDApplication::syslog(rd_config,LOG_WARNING, "JACK protocol version mismatch"); } if((jackstat&JackServerStarted)!=0) { fprintf (stderr, "JACK server started\n"); RDApplication::syslog(rd_config,LOG_WARNING,"JACK server started"); } if((jackstat&JackServerFailed)!=0) { fprintf (stderr, "unable to communication with JACK server\n"); RDApplication::syslog(rd_config,LOG_WARNING, "unable to communicate with JACK server"); } if((jackstat&JackNameNotUnique)!=0) { fprintf (stderr, "JACK client name not unique\n"); RDApplication::syslog(rd_config,LOG_WARNING, "JACK client name not unique"); } if((jackstat&JackFailure)!=0) { fprintf (stderr, "JACK general failure\n"); RDApplication::syslog(rd_config,LOG_WARNING,"JACK general failure"); } jack_card=-1; fprintf (stderr, "no connection to JACK server\n"); RDApplication::syslog(rd_config,LOG_WARNING,"no connection to JACK server"); return; } jack_connected=true; jack_set_process_callback(jack_client,JackProcess,0); jack_set_sample_rate_callback(jack_client,JackSampleRate,0); //jack_set_port_connect_callback(jack_client,JackPortConnectCB,this); #ifdef HAVE_JACK_INFO_SHUTDOWN jack_on_info_shutdown(jack_client,JackInfoShutdown,0); #else jack_on_shutdown(jack_client,JackShutdown,0); #endif // HAVE_JACK_INFO_SHUTDOWN RDApplication::syslog(rd_config,LOG_INFO,"connected to JACK server"); // // Start JACK Clients // jack_client_start_timer=new QTimer(this); connect(jack_client_start_timer,SIGNAL(timeout()), this,SLOT(jackClientStartData())); jack_client_start_timer->start(6000,true); // // Tell the database about us // if(jack_connected) { station->setCardDriver(jack_card,RDStation::Jack); station->setCardName(jack_card,"JACK Audio Connection Kit"); station->setCardInputs(jack_card,RD_MAX_PORTS); station->setCardOutputs(jack_card,RD_MAX_PORTS); } // // Initialize Data Structures // for(int i=0;isetMapping(jack_stop_timer[i],i); connect(jack_stop_timer[i],SIGNAL(timeout()),stop_mapper,SLOT(map())); jack_fade_timer[i]=new QTimer(this); fade_mapper->setMapping(jack_fade_timer[i],i); connect(jack_fade_timer[i],SIGNAL(timeout()),fade_mapper,SLOT(map())); } for(int i=0;isetMapping(jack_record_timer[i],i); connect(jack_record_timer[i],SIGNAL(timeout()),record_mapper,SLOT(map())); } // // Register Ports // for(int i=0;ijackPorts();i++) { name=QString().sprintf("playout_%dL",i); jack_output_port[i][0]= jack_port_register(jack_client,(const char *)name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal,0); name=QString().sprintf("playout_%dR",i); jack_output_port[i][1]= jack_port_register(jack_client,(const char *)name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal,0); name=QString().sprintf("record_%dL",i); jack_input_port[i][0]= jack_port_register(jack_client,(const char *)name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal,0); name=QString().sprintf("record_%dR",i); jack_input_port[i][1]= jack_port_register(jack_client,(const char *)name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal,0); } // // Allocate Temporary Buffers // JackInitCallback(); jack_wave_buffer=new short[RINGBUFFER_SIZE]; jack_wave32_buffer=new int[RINGBUFFER_SIZE]; jack_wave24_buffer=new uint8_t[RINGBUFFER_SIZE]; jack_sample_buffer=new jack_default_audio_sample_t[RINGBUFFER_SIZE]; // // Join the Graph // if(jack_activate(jack_client)) { return; } jack_sample_rate=jack_get_sample_rate(jack_client); if(jack_sample_rate!=system_sample_rate) { fprintf (stderr,"JACK sample rate mismatch!\n"); RDApplication::syslog(rd_config,LOG_WARNING,"JACK sample rate mismatch!"); } jack_activated=true; cae_driver[jack_card]=RDStation::Jack; JackSessionSetup(); #endif // JACK } void MainObject::jackFree() { #ifdef JACK for(int i=0;ikill(); delete jack_clients[i]; } jack_clients.clear(); if(jack_activated) { jack_deactivate(jack_client); } #endif // JACK } bool MainObject::jackLoadPlayback(int card,QString wavename,int *stream) { #ifdef JACK if((*stream=GetJackOutputStream())<0) { RDApplication::syslog(rd_config,LOG_DEBUG, "jackLoadPlayback(%s) GetJackOutputStream():%d <0", (const char *)wavename.toUtf8(),*stream); return false; } jack_play_wave[*stream]=new RDWaveFile(wavename); if(!jack_play_wave[*stream]->openWave()) { RDApplication::syslog(rd_config,LOG_DEBUG, "jackLoadPlayback(%s) openWave() failed to open file", (const char *)wavename.toUtf8()); delete jack_play_wave[*stream]; jack_play_wave[*stream]=NULL; FreeJackOutputStream(*stream); *stream=-1; return false; } switch(jack_play_wave[*stream]->getFormatTag()) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_VORBIS: break; case WAVE_FORMAT_MPEG: InitMadDecoder(card,*stream,jack_play_wave[*stream]); break; default: RDApplication::syslog(rd_config,LOG_DEBUG, "jackLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed", (const char *) wavename.toUtf8(), jack_play_wave[*stream]->getFormatTag(), jack_play_wave[*stream]->getBitsPerSample()); delete jack_play_wave[*stream]; jack_play_wave[*stream]=NULL; FreeJackOutputStream(*stream); *stream=-1; return false; } jack_output_channels[*stream]=jack_play_wave[*stream]->getChannels(); jack_output_sample_rate[*stream]=jack_play_wave[*stream]->getSamplesPerSec(); jack_stopping[*stream]=false; jack_offset[*stream]=0; jack_output_pos[*stream]=0; jack_eof[*stream]=false; FillJackOutputStream(*stream); return true; #else return false; #endif // JACK } bool MainObject::jackUnloadPlayback(int card,int stream) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_STREAMS)){ return false; } if(jack_play_ring[stream]==NULL) { return false; } jack_playing[stream]=false; switch(jack_play_wave[stream]->getFormatTag()) { case WAVE_FORMAT_MPEG: FreeMadDecoder(card,stream); break; } jack_play_wave[stream]->closeWave(); delete jack_play_wave[stream]; jack_play_wave[stream]=NULL; FreeJackOutputStream(stream); return true; #else return false; #endif // JACK } bool MainObject::jackPlaybackPosition(int card,int stream,unsigned pos) { #ifdef JACK unsigned offset=0; if ((stream <0) || (stream >= RD_MAX_STREAMS)){ return false; } jack_eof[stream]=false; jack_play_ring[stream]->reset(); switch(jack_play_wave[stream]->getFormatTag()) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_VORBIS: offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()* (double)jack_play_wave[stream]->getBlockAlign()* (double)pos/1000); jack_offset[stream]=offset/jack_play_wave[stream]->getBlockAlign(); offset=jack_offset[stream]*jack_play_wave[stream]->getBlockAlign(); break; case WAVE_FORMAT_MPEG: offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()* (double)pos/1000); jack_offset[stream]=offset/1152*1152; offset=jack_offset[stream]/1152*jack_play_wave[stream]->getBlockAlign(); FreeMadDecoder(jack_card,stream); InitMadDecoder(jack_card,stream,jack_play_wave[stream]); break; } if(jack_offset[stream]>(int)jack_play_wave[stream]->getSampleLength()) { return false; } jack_output_pos[stream]=0; jack_play_wave[stream]->seekWave(offset,SEEK_SET); FillJackOutputStream(stream); if(jack_playing[stream]) { jack_stop_timer[stream]->stop(); jack_stop_timer[stream]-> start(jack_play_wave[stream]->getExtTimeLength()-pos,true); } return true; #else return false; #endif // JACK } bool MainObject::jackPlay(int card,int stream,int length,int speed,bool pitch, bool rates) { #ifdef JACK if((stream <0) || (stream >= RD_MAX_STREAMS) || (jack_play_ring[stream]==NULL)||jack_playing[stream]) { return false; } if(speed!=RD_TIMESCALE_DIVISOR) { jack_st_conv[stream]=new soundtouch::SoundTouch(); jack_st_conv[stream]->setTempo((float)speed/RD_TIMESCALE_DIVISOR); jack_st_conv[stream]->setSampleRate(jack_output_sample_rate[stream]); jack_st_conv[stream]->setChannels(jack_output_channels[stream]); } jack_playing[stream]=true; if(length>0) { jack_stop_timer[stream]->start(length,true); } statePlayUpdate(card,stream,1); return true; #else return false; #endif // JACK } bool MainObject::jackStopPlayback(int card,int stream) { #ifdef JACK if((stream <0) || (stream>=RD_MAX_STREAMS) || (jack_play_ring[stream]==NULL)||(!jack_playing[stream])) { return false; } jack_playing[stream]=false; jack_stop_timer[stream]->stop(); statePlayUpdate(card,stream,2); return true; #else return false; #endif // JACK } bool MainObject::jackTimescaleSupported(int card) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackLoadRecord(int card,int stream,int coding,int chans, int samprate,int bitrate,QString wavename) { #ifdef JACK jack_record_wave[stream]=new RDWaveFile(wavename); switch(coding) { case 0: // PCM16 jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM); jack_record_wave[stream]->setChannels(chans); jack_record_wave[stream]->setSamplesPerSec(samprate); jack_record_wave[stream]->setBitsPerSample(16); break; case 4: // PCM24 jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM); jack_record_wave[stream]->setChannels(chans); jack_record_wave[stream]->setSamplesPerSec(samprate); jack_record_wave[stream]->setBitsPerSample(24); break; case 2: // MPEG Layer 2 if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) { delete jack_record_wave[stream]; jack_record_wave[stream]=NULL; return false; } jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_MPEG); jack_record_wave[stream]->setChannels(chans); jack_record_wave[stream]->setSamplesPerSec(samprate); jack_record_wave[stream]->setBitsPerSample(16); jack_record_wave[stream]->setHeadLayer(ACM_MPEG_LAYER2); switch(chans) { case 1: jack_record_wave[stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL); break; case 2: jack_record_wave[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 jack_record_wave[stream]; jack_record_wave[stream]=NULL; return false; } jack_record_wave[stream]->setHeadBitRate(bitrate); jack_record_wave[stream]->setMextChunk(true); jack_record_wave[stream]->setMextHomogenous(true); jack_record_wave[stream]->setMextPaddingUsed(false); jack_record_wave[stream]->setMextHackedBitRate(true); jack_record_wave[stream]->setMextFreeFormat(false); jack_record_wave[stream]-> setMextFrameSize(144*jack_record_wave[stream]->getHeadBitRate()/ jack_record_wave[stream]->getSamplesPerSec()); jack_record_wave[stream]->setMextAncillaryLength(5); jack_record_wave[stream]->setMextLeftEnergyPresent(true); if(chans>1) { jack_record_wave[stream]->setMextRightEnergyPresent(true); } else { jack_record_wave[stream]->setMextRightEnergyPresent(false); } jack_record_wave[stream]->setMextPrivateDataPresent(false); break; default: RDApplication::syslog(rd_config,LOG_WARNING, "requested invalid audio encoding %d, card: %d, stream: %d", coding,card,stream); delete jack_record_wave[stream]; jack_record_wave[stream]=NULL; return false; } jack_record_wave[stream]->setBextChunk(true); jack_record_wave[stream]->setLevlChunk(true); if(!jack_record_wave[stream]->createWave()) { delete jack_record_wave[stream]; jack_record_wave[stream]=NULL; return false; } chown((const char *)wavename,rd_config->uid(),rd_config->gid()); jack_input_channels[stream]=chans; jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE); jack_record_ring[stream]->reset(); jack_ready[stream]=true; return true; /* if ((stream <0) || (stream >=RD_MAX_PORTS)){ return false; } jack_record_wave[stream]=new RDWaveFile(wavename); jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM); jack_record_wave[stream]->setChannels(chans); jack_record_wave[stream]->setSamplesPerSec(samprate); jack_record_wave[stream]->setBitsPerSample(16); jack_record_wave[stream]->setBextChunk(true); jack_record_wave[stream]->setLevlChunk(true); if(!jack_record_wave[stream]->createWave()) { delete jack_record_wave[stream]; jack_record_wave[stream]=NULL; return false; } chown((const char *)wavename,rd_config->uid(),rd_config->gid()); jack_input_channels[stream]=chans; jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE); jack_record_ring[stream]->reset(); jack_ready[stream]=true; return true; */ #else return false; #endif // JACK } bool MainObject::jackUnloadRecord(int card,int stream,unsigned *len) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_PORTS)){ return false; } jack_recording[stream]=false; jack_ready[stream]=false; EmptyJackInputStream(stream,true); *len=jack_samples_recorded[stream]; jack_samples_recorded[stream]=0; jack_record_wave[stream]->closeWave(*len); delete jack_record_wave[stream]; jack_record_wave[stream]=NULL; delete jack_record_ring[stream]; jack_record_ring[stream]=NULL; FreeTwoLameEncoder(card,stream); return true; #else return false; #endif // JACK } bool MainObject::jackRecord(int card,int stream,int length,int thres) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_PORTS)){ return false; } if(!jack_ready[stream]) { return false; } jack_recording[stream]=true; if(jack_input_vox[stream]==0.0) { if(length>0) { jack_record_timer[stream]->start(length,true); } stateRecordUpdate(card,stream,4); } return true; #else return false; #endif // JACK } bool MainObject::jackStopRecord(int card,int stream) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_PORTS)){ return false; } if(!jack_recording[stream]) { return false; } jack_recording[stream]=false; return true; #else return false; #endif // JACK } bool MainObject::jackSetInputVolume(int card,int stream,int level) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_STREAMS)){ return false; } if(level>-10000) { jack_input_volume[stream]= (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0); jack_input_volume_db[stream]=level; } else { jack_input_volume[stream]=0.0; jack_input_volume_db[stream]=-10000; } return true; #else return false; #endif // JACK } bool MainObject::jackSetOutputVolume(int card,int stream,int port,int level) { #ifdef JACK if ((stream <0) ||(stream >= RD_MAX_STREAMS) || (port <0) || (port >= RD_MAX_PORTS)){ return false; } if(level>-10000) { jack_output_volume[port][stream]= (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0); jack_output_volume_db[port][stream]=level; } else { jack_output_volume[port][stream]=0.0; jack_output_volume_db[port][stream]=-10000; } return true; #else return false; #endif // JACK } bool MainObject::jackFadeOutputVolume(int card,int stream,int port,int level, int length) { #ifdef JACK int diff; if ((stream <0) ||(stream >= RD_MAX_STREAMS) || (port <0) || (port >= RD_MAX_PORTS)){ return false; } if(jack_fade_timer[stream]->isActive()) { jack_fade_timer[stream]->stop(); } if(level>jack_output_volume_db[port][stream]) { jack_fade_up[stream]=true; diff=level-jack_output_volume_db[port][stream]; } else { jack_fade_up[stream]=false; diff=jack_output_volume_db[port][stream]-level; } jack_fade_volume_db[stream]=level; jack_fade_port[stream]=port; jack_fade_increment[stream]=diff*RD_JACK_FADE_INTERVAL/length; jack_fade_timer[stream]->start(RD_JACK_FADE_INTERVAL); return true; #else return false; #endif // JACK } bool MainObject::jackSetInputLevel(int card,int port,int level) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackSetOutputLevel(int card,int port,int level) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackSetInputMode(int card,int stream,int mode) { #ifdef JACK jack_input_mode[card][stream]=mode; return true; #else return false; #endif // JACK } bool MainObject::jackSetOutputMode(int card,int stream,int mode) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackSetInputVoxLevel(int card,int stream,int level) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackSetInputType(int card,int port,int type) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackGetInputStatus(int card,int port) { #ifdef JACK return true; #else return false; #endif // JACK } bool MainObject::jackGetInputMeters(int card,int port,short levels[2]) { #ifdef JACK jack_default_audio_sample_t meter; if ((port <0) || (port >= RD_MAX_PORTS)){ return false; } for(int i=0;i<2;i++) { meter=jack_input_meter[port][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(short)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // JACK } bool MainObject::jackGetOutputMeters(int card,int port,short levels[2]) { #ifdef JACK jack_default_audio_sample_t meter; if ((port <0) || (port >= RD_MAX_PORTS)){ return false; } for(int i=0;i<2;i++) { meter=jack_output_meter[port][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(short)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // JACK } bool MainObject::jackGetStreamOutputMeters(int card,int stream,short levels[2]) { #ifdef JACK jack_default_audio_sample_t meter; if ((stream<0) || (stream>=RD_MAX_STREAMS)){ return false; } for(int i=0;i<2;i++) { meter=jack_stream_output_meter[stream][i]->average(); if(meter==0.0) { levels[i]=-10000; } else { levels[i]=(short)(2000.0*log10(meter)); if(levels[i]<-10000) { levels[i]=-10000; } } } return true; #else return false; #endif // JACK } void MainObject::jackGetOutputPosition(int card,unsigned *pos) { #ifdef JACK for(int i=0;igetSamplesPerSec(); } else { pos[i]=0; } } #endif // JACK } bool MainObject::jackSetPassthroughLevel(int card,int in_port,int out_port, int level) { #ifdef JACK if ((in_port <0) || (in_port >= RD_MAX_PORTS) || (out_port <0) || (out_port >= RD_MAX_PORTS)){ return false; } if(level>-10000) { jack_passthrough_volume[in_port][out_port]= (jack_default_audio_sample_t)pow(10.0,(double)level/2000.0); jack_passthrough_volume_db[in_port][out_port]=level; } else { jack_passthrough_volume[in_port][out_port]=0.0; jack_passthrough_volume_db[in_port][out_port]=-10000; } return true; #else return false; #endif // JACK } int MainObject::GetJackOutputStream() { #ifdef JACK for(int i=0;i= RD_MAX_STREAMS)){ return; } delete jack_play_ring[stream]; jack_play_ring[stream]=NULL; if(jack_st_conv[stream]!=NULL) { delete jack_st_conv[stream]; jack_st_conv[stream]=NULL; } #else return; #endif } void MainObject::EmptyJackInputStream(int stream,bool done) { #ifdef JACK if ((stream <0) || (stream >= RD_MAX_STREAMS)){ return; } unsigned n=jack_record_ring[stream]-> read((char *)jack_sample_buffer,jack_record_ring[stream]->readSpace()); WriteJackBuffer(stream,jack_sample_buffer,n,done); #endif // JACK } #ifdef JACK void MainObject::WriteJackBuffer(int stream,jack_default_audio_sample_t *buffer, unsigned len,bool done) { ssize_t s; unsigned char mpeg[2048]; unsigned frames; unsigned n; frames=len/(sizeof(jack_default_audio_sample_t)* jack_record_wave[stream]->getChannels()); jack_samples_recorded[stream]+=frames; switch(jack_record_wave[stream]->getFormatTag()) { case WAVE_FORMAT_PCM: switch(jack_record_wave[stream]->getBitsPerSample()) { case 16: // PCM16 n=len/sizeof(jack_default_audio_sample_t); src_float_to_short_array(buffer,jack_wave_buffer,n); jack_record_wave[stream]->writeWave(jack_wave_buffer,n*sizeof(short)); break; case 24: // PCM24 n=len/sizeof(jack_default_audio_sample_t); src_float_to_int_array(buffer,jack_wave32_buffer,n); for(unsigned i=0;iwriteWave(jack_wave24_buffer,n*3); 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_float32_interleaved( twolame_lameopts[jack_card][stream], buffer+i*jack_record_wave[stream]->getChannels(), n,mpeg,2048))>=0) { jack_record_wave[stream]->writeWave(mpeg,s); } else { RDApplication::syslog(rd_config,LOG_WARNING, "TwoLAME encode error, card: %d, stream: %d",jack_card,stream); } } if(done) { if((s=twolame_encode_flush(twolame_lameopts[jack_card][stream], mpeg,2048))>=0) { jack_record_wave[stream]->writeWave(mpeg,s); } } #endif // HAVE_TWOLAME break; } } #endif // JACK void MainObject::FillJackOutputStream(int stream) { #ifdef JACK int n=0; unsigned mpeg_frames=0; unsigned frame_offset=0; int m=0; if ((stream <0) || (stream >= RD_MAX_STREAMS)){ return; } int free= jack_play_ring[stream]->writeSpace()/sizeof(jack_default_audio_sample_t)-1; if((free<=0)||(jack_eof[stream]==true)) { return; } switch(jack_play_wave[stream]->getFormatTag()) { case WAVE_FORMAT_PCM: switch(jack_play_wave[stream]->getBitsPerSample()) { case 16: // PMC16 free=(int)free/jack_output_channels[stream]*jack_output_channels[stream]; n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/ sizeof(short); if((n!=free)&&(jack_st_conv[stream]==NULL)) { jack_eof[stream]=true; jack_stop_timer[stream]->stop(); } src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n); break; case 24: // PMC24 free=(int)free/jack_output_channels[stream]*jack_output_channels[stream]; n=jack_play_wave[stream]->readWave(jack_wave24_buffer,3*free)/3; if((n!=free)&&(jack_st_conv[stream]==NULL)) { jack_eof[stream]=true; jack_stop_timer[stream]->stop(); } for(int i=0;ireadWave(jack_wave_buffer,sizeof(short)*free)/ sizeof(short); if((n!=free)&&(jack_st_conv[stream]==NULL)) { jack_eof[stream]=true; jack_stop_timer[stream]->stop(); } src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n); break; case WAVE_FORMAT_MPEG: #ifdef HAVE_MAD mpeg_frames=free/(1152*jack_output_channels[stream]); free=mpeg_frames*1152*jack_output_channels[stream]; for(unsigned i=0;i readWave(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream], mad_frame_size[jack_card][stream]); if(m==mad_frame_size[jack_card][stream]) { mad_stream_buffer(&mad_stream[jack_card][stream], mad_mpeg[jack_card][stream], m+mad_left_over[jack_card][stream]); while(mad_frame_decode(&mad_frame[jack_card][stream], &mad_stream[jack_card][stream])==0) { mad_synth_frame(&mad_synth[jack_card][stream], &mad_frame[jack_card][stream]); n+=(jack_output_channels[stream]* mad_synth[jack_card][stream].pcm.length); for(int j=0;jstop(); continue; } mad_left_over[jack_card][stream]= mad_stream[jack_card][stream].bufend- mad_stream[jack_card][stream].next_frame; memmove(mad_mpeg[jack_card][stream], mad_stream[jack_card][stream].next_frame, mad_left_over[jack_card][stream]); } #endif // HAVE_MAD break; } if(jack_st_conv[stream]==NULL) { jack_play_ring[stream]-> write((char *)jack_sample_buffer,n*sizeof(jack_default_audio_sample_t)); } else { jack_st_conv[stream]-> putSamples(jack_sample_buffer,n/jack_output_channels[stream]); free=jack_play_ring[stream]->writeSpace()/ (sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1; while((n=jack_st_conv[stream]-> receiveSamples(jack_sample_buffer,free))>0) { jack_play_ring[stream]-> write((char *)jack_sample_buffer,n* sizeof(jack_default_audio_sample_t)* jack_output_channels[stream]); free=jack_play_ring[stream]->writeSpace()/ (sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1; } if((jack_st_conv[stream]->numSamples()==0)&& (jack_st_conv[stream]->numUnprocessedSamples()==0)) { jack_eof[stream]=true; jack_stop_timer[stream]->stop(); } } #endif // JACK } void MainObject::JackClock() { #ifdef JACK for(int i=0;isetSource(RD_CONF_FILE); bool src_ok=false; bool dest_ok=false; QString src_tag="Source1"; QString dest_tag="Destination1"; QString src=profile->stringValue("JackSession",src_tag,"",&src_ok); QString dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok); while(src_ok&&dest_ok) { if(jack_connect(jack_client,(const char *)src,(const char *)dest)!=0) { RDApplication::syslog(rd_config,LOG_WARNING,"unable to connect %s to %s", (const char *)src.toUtf8(),(const char *)dest.toUtf8()); } count++; src_tag=QString().sprintf("Source%d",count+1); dest_tag=QString().sprintf("Destination%d",count+1); src=profile->stringValue("JackSession",src_tag,"",&src_ok); dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok); } delete profile; #endif // JACK }