PosibErr<void> setup_filter(Filter & filter, Config * config, bool use_decoder, bool use_filter, bool use_encoder) { StringList sl; config->retrieve_list("filter", &sl); StringListEnumeration els = sl.elements_obj(); const char * filter_name; String fun; StackPtr<IndividualFilter> ifilter; filter.clear(); while ((filter_name = els.next()) != 0) { //fprintf(stderr, "Loading %s ... \n", filter_name); FilterEntry * f = get_standard_filter(filter_name); // In case libdl is not available a filter is only available if made // one of the standard filters. This is done by statically linking // the filter sources. // On systems providing libdl or in case libtool mimics libdl // The following code parts assure that all filters needed and requested // by user are loaded properly or be reported to be missing. // FilterHandle decoder_handle, filter_handle, encoder_handle; #ifdef HAVE_LIBDL FilterEntry dynamic_filter; if (!f) { RET_ON_ERR_SET(get_dynamic_filter(config, filter_name), const ConfigModule *, module); if (!(decoder_handle = dlopen(module->file,RTLD_NOW)) || !(encoder_handle = dlopen(module->file,RTLD_NOW)) || !(filter_handle = dlopen(module->file,RTLD_NOW))) return make_err(cant_dlopen_file,dlerror()).with_file(filter_name); fun = "new_aspell_"; fun += filter_name; fun += "_decoder"; dynamic_filter.decoder = (FilterFun *)dlsym(decoder_handle.get(), fun.str()); fun = "new_aspell_"; fun += filter_name; fun += "_encoder"; dynamic_filter.encoder = (FilterFun *)dlsym(encoder_handle.get(), fun.str()); fun = "new_aspell_"; fun += filter_name; fun += "_filter"; dynamic_filter.filter = (FilterFun *)dlsym(filter_handle.get(), fun.str()); if (!dynamic_filter.decoder && !dynamic_filter.encoder && !dynamic_filter.filter) return make_err(empty_filter,filter_name); dynamic_filter.name = filter_name; f = &dynamic_filter; } #else if (!f) return make_err(no_such_filter, filter_name); #endif if (use_decoder && f->decoder && (ifilter = f->decoder())) { RET_ON_ERR_SET(ifilter->setup(config), bool, keep); ifilter->handle = decoder_handle.release(); if (!keep) { ifilter.del(); } else { filter.add_filter(ifilter.release()); } } if (use_filter && f->filter && (ifilter = f->filter())) { RET_ON_ERR_SET(ifilter->setup(config), bool, keep); ifilter->handle = filter_handle.release(); if (!keep) { ifilter.del(); } else { filter.add_filter(ifilter.release()); } }
/** * The playback thread code * \internal */ void *narrator_thread(void *narrator) { //Narrator *n = static_cast<Narrator *>(narrator); Narrator *n = (Narrator*)narrator; int queueitems; // Set initial values to 0 so that they get updated when thread gets play signal float gain = 0; float tempo = 0; float pitch = 0; PortAudio portaudio; Filter filter; Narrator::threadState state = n->getState(); LOG4CXX_INFO(narratorLog, "Starting playback thread"); do { queueitems = n->numPlaylistItems(); if(queueitems == 0) { // Wait a little before calling callback long waitms = portaudio.getRemainingms(); if(waitms != 0) { LOG4CXX_DEBUG(narratorLog, "Waiting " << waitms << " ms for playback to finish"); while(waitms > 0 && queueitems == 0) { usleep(100000); queueitems = n->numPlaylistItems(); waitms -= 100; } } // Break if we during the pause got some more queued items to play if(queueitems == 0) { if(state != Narrator::DEAD) n->audioFinishedPlaying(); n->setState(Narrator::WAIT); LOG4CXX_INFO(narratorLog, "Narrator in WAIT state"); portaudio.stop(); while(queueitems == 0) { state = n->getState(); if(state == Narrator::EXIT) break; usleep(10000); queueitems = n->numPlaylistItems(); } } LOG4CXX_INFO(narratorLog, "Narrator starting playback"); } if(state == Narrator::EXIT) break; n->setState(Narrator::PLAY); n->bResetFlag = false; Narrator::PlaylistItem pi; pthread_mutex_lock(n->narratorMutex); if(n->mPlaylist.size() > 0) { pi = n->mPlaylist.front(); n->mPlaylist.pop(); } else { LOG4CXX_ERROR(narratorLog, "Narrator started playback thread without playlistitems"); pthread_mutex_unlock(n->narratorMutex); continue; } string lang = n->mLanguage; pthread_mutex_unlock(n->narratorMutex); // If trying to play a file, open it if(pi.mClass == "file") { LOG4CXX_DEBUG(narratorLog, "Playing file: " << pi.mIdentifier); AudioStream *audioStream; std::string fileExtension = getFileExtension(pi.mIdentifier); if (fileExtension == "ogg") { audioStream = new OggStream; } else if (fileExtension == "mp3") { audioStream = new Mp3Stream; } else { LOG4CXX_ERROR(narratorLog, "extension '" << fileExtension << "' not supported"); continue; } if(!audioStream->open(pi.mIdentifier)) { LOG4CXX_ERROR(narratorLog, "error opening audio stream: " << pi.mIdentifier); audioStream->close(); continue; } if (portaudio.getRate() != audioStream->getRate()) { long waitms = portaudio.getRemainingms(); if (waitms != 0) { LOG4CXX_DEBUG(narratorLog, "Waiting for current playback to finish"); while (waitms > 0) { usleep(100000); waitms -= 100; } } } if(!portaudio.open(audioStream->getRate(), audioStream->getChannels())) { LOG4CXX_ERROR(narratorLog, "error initializing portaudio, (rate: " << audioStream->getRate() << " channels: " << audioStream->getChannels() << ")"); continue; } if(!filter.open(audioStream->getRate(), audioStream->getChannels())) { LOG4CXX_ERROR(narratorLog, "error initializing filter"); continue; } LOG4CXX_DEBUG(narratorLog, "Audio stream has " << audioStream->getChannels() << " channel(s) and rate " << audioStream->getRate() << " Hz"); int inSamples = 0; soundtouch::SAMPLETYPE* buffer = new soundtouch::SAMPLETYPE[audioStream->getChannels()*BUFFERSIZE]; //buffer = (short*)malloc(sizeof(short) * 2 * BUFFERSIZE); // long totalSamplesRead = 0; do { // change gain, tempo and pitch adjustGainTempoPitch(n, filter, gain, tempo, pitch); // read some stuff from the audio stream inSamples = audioStream->read(buffer, BUFFERSIZE/**audioStream->getChannels()*/); LOG4CXX_TRACE(narratorLog, "got " << inSamples << " samples"); //printf("Read %d samples from audio stream\n", inSamples); if(inSamples != 0) { filter.write(buffer, inSamples); // One sample contains data for all channels here writeSamplesToPortaudio( n, portaudio, filter, buffer ); } else { LOG4CXX_INFO(narratorLog, "Flushing soundtouch buffer"); filter.flush(); } state = n->getState(); } while (inSamples != 0 && state == Narrator::PLAY && !n->bResetFlag); if(buffer != NULL) delete [] (buffer); audioStream->close(); delete audioStream; } // Else try opening from database else { vector <MessageAudio> vAudioQueue; // Get a list of MessageAudio objects to play Message *m = pi.mMessage; if(m==NULL){ LOG4CXX_ERROR(narratorLog, "Message was null"); } m->setLanguage(lang); m->load(pi.mIdentifier, pi.mClass); if(!m->compile() || !m->hasAudio()) { LOG4CXX_ERROR(narratorLog, "Narrator translation not found: could not find audio for '" << pi.mIdentifier << "'"); } else { vAudioQueue = m->getAudioQueue(); } // Play what we got if(vAudioQueue.size() > 0) { vector <MessageAudio>::iterator audio; audio = vAudioQueue.begin(); do { LOG4CXX_INFO(narratorLog, "Saying: " << audio->getText()); AudioStream *audioStream; std::string encoding = ((MessageAudio&)*audio).getEncoding(); if (encoding == "ogg") { audioStream = new OggStream; } else if (encoding == "mp3") { audioStream = new Mp3Stream; } else { LOG4CXX_ERROR(narratorLog, "encoding '" << encoding << "' not supported"); audio++; continue; } if(!audioStream->open(*audio)) { LOG4CXX_ERROR(narratorLog, "error opening audio stream"); audioStream->close(); break; } if (portaudio.getRate() != audioStream->getRate()) { long waitms = portaudio.getRemainingms(); if (waitms != 0) { LOG4CXX_DEBUG(narratorLog, "Waiting for current playback to finish"); while (waitms > 0) { usleep(100000); waitms -= 100; } } } if(!portaudio.open(audioStream->getRate(), audioStream->getChannels())) { LOG4CXX_ERROR(narratorLog, "error initializing portaudio"); break; } if(!filter.open(audioStream->getRate(), audioStream->getChannels())) { LOG4CXX_ERROR(narratorLog, "error initializing filter"); break; } int inSamples = 0; soundtouch::SAMPLETYPE* buffer = new soundtouch::SAMPLETYPE[audioStream->getChannels()*BUFFERSIZE]; do { // change gain, tempo and pitch adjustGainTempoPitch(n, filter, gain, tempo, pitch); // read some stuff from the audio stream inSamples = audioStream->read(buffer, BUFFERSIZE*audioStream->getChannels()); if(inSamples != 0) { filter.write(buffer, inSamples); writeSamplesToPortaudio( n, portaudio, filter, buffer ); } else { LOG4CXX_INFO(narratorLog, "Flushing soundtouch buffer"); filter.flush(); } state = n->getState(); } while (inSamples != 0 && state == Narrator::PLAY && !n->bResetFlag); if(buffer != NULL) delete [] (buffer); audioStream->close(); audio++; } while(audio != vAudioQueue.end() && state == Narrator::PLAY && !n->bResetFlag); } //Cleanup message object delete(pi.mMessage); } // Abort stream? if(n->bResetFlag) { n->bResetFlag = false; portaudio.stop(); filter.clear(); } } while(state != Narrator::EXIT); LOG4CXX_INFO(narratorLog, "Shutting down playbackthread"); pthread_exit(NULL); return NULL; }