void PulseOutput::close() { #ifdef DEBUG context->getReactor().debug(); #endif if (stream) { GM_DEBUG_PRINT("[pulse] disconnecting stream\n"); pa_stream_disconnect(stream); pa_stream_unref(stream); stream=nullptr; } if (pulse_context) { GM_DEBUG_PRINT("[pulse] disconnecting context\n"); pa_context_disconnect(pulse_context); pa_context_unref(pulse_context); pulse_context=nullptr; } #ifdef DEBUG context->getReactor().debug(); #endif delete pa_io_event::recycle; delete pa_time_event::recycle; delete pa_defer_event::recycle; pa_io_event::recycle = nullptr; pa_time_event::recycle = nullptr; pa_defer_event::recycle = nullptr; pulsevolume = PA_VOLUME_MUTED; af.reset(); }
FXbool MMSInput::open(const FXString & uri) { mms=mms_connect(NULL,NULL,uri.text(),128*1024); if (!mms) { GM_DEBUG_PRINT("failed to connect\n"); return false; } GM_DEBUG_PRINT("mms connected\n"); return true; }
DBusHandlerResult dbus_status_item_filter(DBusConnection *connection,DBusMessage * msg,void */* data*/){ // DEBUG_DBUS_MESSAGE(msg); DBusMessage * reply; DBusMessageIter iter; DBusMessageIter dict; //DBusMessageIter dictentry; FXuint serial; if (dbus_message_has_path(msg,APPLICATION_STATUS_ITEM_PATH)){ DEBUG_DBUS_MESSAGE(msg); if (dbus_message_has_interface(msg,APPLICATION_STATUS_ITEM_INTERFACE)) { if (dbus_message_is_method_call(msg,APPLICATION_STATUS_ITEM_INTERFACE,"Activate")){ GMPlayerManager::instance()->cmd_toggle_shown(); return gm_dbus_reply_if_needed(connection,msg); } else if (dbus_message_is_method_call(msg,APPLICATION_STATUS_ITEM_INTERFACE,"Scroll")){ FXint delta; const FXchar * orientation; if (dbus_message_get_args(msg,NULL,DBUS_TYPE_INT32,&delta,DBUS_TYPE_STRING,&orientation,DBUS_TYPE_INVALID)) { //FIXME FXint level = GMPlayerManager::instance()->volume(); level+=(delta/120); GMPlayerManager::instance()->volume(level); } return gm_dbus_reply_if_needed(connection,msg); } } else if (dbus_message_has_interface(msg,DBUS_INTERFACE_INTROSPECTABLE)) { if (dbus_message_is_method_call(msg,DBUS_INTERFACE_INTROSPECTABLE,"Introspect")){ return gm_dbus_reply_string(connection,msg,appstatus_xml); } } else if (dbus_message_has_interface(msg,DBUS_INTERFACE_PROPERTIES)) { if (dbus_message_is_method_call(msg,DBUS_INTERFACE_PROPERTIES,"Get")){ GM_DEBUG_PRINT("get\n"); } else if (dbus_message_is_method_call(msg,DBUS_INTERFACE_PROPERTIES,"GetAll")){ if ((reply=dbus_message_new_method_return(msg))!=NULL) { dbus_message_iter_init_append(reply,&iter); dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,"{sv}",&dict); gm_dbus_dict_append_path(&dict,"Menu",APPLICATION_STATUS_ITEM_MENU_PATH); gm_dbus_dict_append_string(&dict,"Category","ApplicationStatus"); gm_dbus_dict_append_string(&dict,"Id","gogglesmm"); gm_dbus_dict_append_string(&dict,"IconName","gogglesmm"); gm_dbus_dict_append_string(&dict,"Status","Active"); gm_dbus_dict_append_uint32(&dict,"WindowId",GMPlayerManager::instance()->getMainWindowId()); gm_add_tooltip(&dict); dbus_message_iter_close_container(&iter,&dict); dbus_connection_send(connection,reply,&serial); dbus_message_unref(reply); } return DBUS_HANDLER_RESULT_HANDLED; } else if (dbus_message_is_method_call(msg,DBUS_INTERFACE_PROPERTIES,"Set")){ } } } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
ID3V2::ID3V2(FXuchar *b,FXint len) : buffer(b),size(len),p(0),padstart(0),padend(0),length(-1) { const FXchar & flags = buffer[5]; version = buffer[3]; GM_DEBUG_PRINT("[id3v2] version %d\n",version); buffer+=10; size-=10; /// we can skip the footer if (version>=4 && flags&HAS_FOOTER) size-=10; /// Apply unsync, according to spec 2.3, the extended header also needs unsyncing if (flags&HAS_UNSYNC) { unsync(buffer,size); } /// skip the extended header if (version>=3 && flags&HAS_EXTENDED_HEADER) { FXint header_size; if (version==3) header_size = ID3_INT32(buffer); else header_size = ID3_SYNCSAFE_INT32(buffer); buffer+=header_size; } /// Parse p=0; while(p<size) parse_frame(); }
void InputThread::ctrl_eos() { GM_DEBUG_PRINT("[input] end of stream reached\n"); if (state!=StateProcessing) { //ctrl_flush(true); ctrl_close_input(true); } }
void ID3V2::parse_comment_frame(FXint framesize) { FXString key,field; const FXuchar & encoding = buffer[p]; const FXchar* textstart = (const FXchar*)(buffer+p+4); const FXint textlength = framesize - 4; if (encoding==UTF16_BOM || encoding==UTF16) { FXint ksize = strwlen(textstart,textlength); FXint vsize = strwlen(textstart+ksize+2,textlength-ksize-2); parse_text(encoding,textstart,ksize,key); parse_text(encoding,textstart+ksize+2,vsize,field); } else { FXint ksize = strnlen(textstart,textlength); FXint vsize = strnlen(textstart+ksize+1,textlength-ksize-1); parse_text(encoding,textstart,ksize,key); parse_text(encoding,textstart+ksize+1,vsize,field); } FXString comment = key + " " + field; if (comment.find("iTunSMPB")>=0) { comment.simplify().scan("iTunSMPB %*x %hx %hx %lx",&padstart,&padend,&length); GM_DEBUG_PRINT("[id3v2] found iTunSMPB (padding %d %d, length %ld)\n",padstart,padend,length); } }
void InputThread::ctrl_open_inputs(const FXStringList & urls){ for (FXint i=0;i<urls.no();i++){ GM_DEBUG_PRINT("[input] ctrl_open_inputs[%d] %s\n",i,urls[i].text()); if (urls[i].empty()) continue; /// Open Input input=open_input(urls[i]); if (input==NULL) { if (aborted()) break; continue; } /// Open Reader reader = open_reader(); if (reader==NULL) continue; if (!reader->init(input)) continue; streamid++; set_state(StateProcessing,true); return; } ctrl_close_input(); set_state(StateIdle,true); }
long GMNotifyDaemon::onNotifyCapabilities(FXObject*,FXSelector,void*ptr){ DBusMessage * msg = static_cast<DBusMessage*>(ptr); FXchar ** caps = NULL; int ncaps; if ((dbus_message_get_type(msg)==DBUS_MESSAGE_TYPE_METHOD_RETURN) && dbus_message_get_args(msg,NULL,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING,&caps,&ncaps,DBUS_TYPE_INVALID)) { FXbool has_action_icons=false; FXbool has_actions=false; FXbool has_persistence=false; for (FXint i=0;i<ncaps;i++){ GM_DEBUG_PRINT("caps[%d]=%s\n",i,caps[i]); if (flags&ACTION_ITEMS) { if (comparecase(caps[i],"actions")==0) has_actions=true; else if ((comparecase(caps[i],"action-icons")==0) || (comparecase(caps[i],"x-gnome-icon-buttons")==0)) has_action_icons=true; else if (comparecase(caps[i],"persistence")==0) has_persistence=true; } } if (has_actions && has_action_icons && has_persistence) { persistent=true; reset(); } // Need to delete array of strings returned by dbus_message_get_args dbus_free_string_array(caps); } return 1; }
void InputThread::ctrl_open_input(const FXString & uri) { GM_DEBUG_PRINT("[input] ctrl_open_input %s\n",uri.text()); if (uri.empty()) { goto failed; } /// Open Input input=open_input(uri); if (input==NULL) { engine->post(new ErrorMessage(FXString::value("Unable to open %s",uri.text()))); goto failed; } reader = open_reader(); if (reader==NULL) { engine->post(new ErrorMessage(FXString::value("No input plugin available for %s",uri.text()))); goto failed; } if (!reader->init(input)) { engine->post(new ErrorMessage(FXString::value("Failed to initialize plugin"))); goto failed; } streamid++; set_state(StateProcessing,true); return; failed: ctrl_close_input(); set_state(StateIdle,true); }
FXbool VorbisDecoder::init_decoder() { const FXuchar * data_ptr = get_packet_offset(); // Initialize Info init_info(); while(get_next_packet()) { if (is_vorbis_header()) { if (vorbis_synthesis_headerin(&info,&comment,&op)<0) { GM_DEBUG_PRINT("[vorbis] vorbis_synthesis_headerin failed\n"); return false; } } else { // First non header if (vorbis_synthesis_init(&dsp,&info)<0) return false; if (vorbis_block_init(&dsp,&block)<0) { vorbis_dsp_clear(&dsp); return false; } has_dsp=true; push_back_packet(); return true; } } vorbis_info_clear(&info); set_packet_offset(data_ptr); return true; }
void HttpClient::discard() { GM_DEBUG_PRINT("[http] discard()\n"); if (flags&ConnectionClose) { close(); } else if (io.isOpen()) { HttpResponse::discard(); } }
ReadStatus MP4Reader::parse() { mp4AudioSpecificConfig cfg; FXuchar* buffer; FXuint size; FXint ntracks; FXASSERT(handle==NULL); FXASSERT(packet); handle = mp4ff_open_read(&callback); if (handle==NULL) goto error; ntracks = mp4ff_total_tracks(handle); if (ntracks<=0) goto error; for (FXint i=0;i<ntracks;i++) { if ((mp4ff_get_decoder_config(handle,i,&buffer,&size)==0) && buffer && size) { if (NeAACDecAudioSpecificConfig(buffer,size,&cfg)==0) { af.set(AP_FORMAT_S16,mp4ff_get_sample_rate(handle,i),mp4ff_get_channel_count(handle,i)); af.debug(); if (size>packet->space()) { GM_DEBUG_PRINT("MP4 config buffer is too big for decoder packet"); free(buffer); goto error; } track=i; frame=0; nframes=mp4ff_num_samples(handle,i); stream_length=mp4ff_get_track_duration(handle,i); packet->append(buffer,size); packet->flags|=AAC_FLAG_CONFIG|AAC_FLAG_FRAME; engine->decoder->post(new ConfigureEvent(af,Codec::AAC)); send_meta(); engine->decoder->post(packet); packet=NULL; flags|=FLAG_PARSED; free(buffer); return ReadOk; } free(buffer); } } error: packet->unref(); return ReadError; }
void AudioEngine::exit() { if (input->running()) { GM_DEBUG_PRINT("AudioEngine::exit()\n"); input->post(new ControlEvent(Ctrl_Quit),EventQueue::Flush); GM_DEBUG_PRINT("Waiting for input\n"); input->join(); GM_DEBUG_PRINT("Waiting for decoder\n"); decoder->join(); GM_DEBUG_PRINT("Waiting for output\n"); output->join(); GM_DEBUG_PRINT("All Joined. Freeing data\n"); input->free(); decoder->free(); output->free(); } }
FXbool PulseOutput::open() { /// Start the mainloop //if (eventloop==nullptr) { // eventloop = new PulseReactor(); // } /// Get a context if (pulse_context==nullptr) { pulse_context = pa_context_new(&api,"Goggles Music Manager"); #ifdef DEBUG pa_context_set_state_callback(pulse_context,context_state_callback,this); #endif pa_context_set_subscribe_callback(pulse_context,context_subscribe_callback,this); } /// Try connecting GM_DEBUG_PRINT("[pulse] pa_context_connect()\n"); if (pa_context_get_state(pulse_context)==PA_CONTEXT_UNCONNECTED) { if (pa_context_connect(pulse_context,nullptr,PA_CONTEXT_NOFLAGS,nullptr)<0) { GM_DEBUG_PRINT("[pulse] pa_context_connect failed\n"); return false; } } /// Wait until we're connected to the pulse daemon GM_DEBUG_PRINT("[pulse] wait for connection\n"); pa_context_state_t state; while((state=pa_context_get_state(pulse_context))!=PA_CONTEXT_READY) { if (state==PA_CONTEXT_FAILED || state==PA_CONTEXT_TERMINATED){ GM_DEBUG_PRINT("[pulse] Unable to connect to pulsedaemon\n"); return false; } context->wait_plugin_events(); } pa_operation* operation = pa_context_subscribe(pulse_context,PA_SUBSCRIPTION_MASK_SINK_INPUT,nullptr,this); if (operation) pa_operation_unref(operation); GM_DEBUG_PRINT("[pulse] ready()\n"); return true; }
void InputThread::set_state(FXuchar s,FXbool notify) { if (state!=s) { state=s; switch(state) { case StateIdle : GM_DEBUG_PRINT("[input] state = idle\n"); break; case StateProcessing: GM_DEBUG_PRINT("[input] state = processing\n"); break; case StateError : GM_DEBUG_PRINT("[input] state = error\n"); break; } } /// Tell front end about the state. if (notify) { switch(state) { case StateError : case StateIdle : engine->post(new Event(AP_STATE_READY)); break; case StateProcessing: engine->post(new Event(AP_STATE_PLAYING)); break; default : break; } } }
void InputThread::ctrl_close_input(FXbool notify) { GM_DEBUG_PRINT("[input] close input %d\n",notify); if (input) { delete input; input=NULL; url.clear(); } if (reader) { delete reader; reader=NULL; } set_state(StateIdle,notify); }
void GMNotifyDaemon::close() { if (msgid>0) { GM_DEBUG_PRINT("GMNotifyDaemon::close()\n"); DBusMessage * msg = method("CloseNotification"); if (msg) { dbus_message_append_args(msg,DBUS_TYPE_UINT32,&msgid,DBUS_TYPE_INVALID); dbus_message_set_no_reply(msg,true); bus->send(msg); // We don't want to wait for NotificationClosed signal. // and we want to prevent calling CloseNotification multiple times. msgid=0; } } }
ReadStatus AACReader::process(Packet*packet) { if (!(flags&FLAG_PARSED)) { GM_DEBUG_PRINT("finding sync\n"); FXuchar buffer[2]; if (input->read(buffer,2)!=2) return ReadError; do { // fxmessage("0x%hhx 0x%hhx\n",buffer[0],buffer[1]); if ((buffer[0]==0xFF) && (buffer[1]&0xf0)==0xf0) { GM_DEBUG_PRINT("found sync\n"); // af.set(AP_FORMAT_S16,44100,2); engine->decoder->post(new ConfigureEvent(af,Codec::AAC)); flags|=FLAG_PARSED; packet->append(buffer,2); break; } buffer[0]=buffer[1]; if (input->read(&buffer[1],1)!=1) return ReadError; } while(1); } return ReaderPlugin::process(packet); }
FXint GMRenameTask::run() { try { for (FXint i=0;i<from.no() && processing;i++) { if (to[i].empty()) continue; if (!FXDir::createDirectories(FXPath::directory(to[i]))) continue; if (FXStat::exists(to[i])) continue; if (FXFile::moveFiles(from[i],to[i])){ database->setTrackFilename(tracks[i],to[i]); } } } catch(GMDatabaseException&) { GM_DEBUG_PRINT("Database Exception\n"); } return 0; }
void WavOutput::close() { if (file.isOpen()) { GM_DEBUG_PRINT("[wav] closed output\n"); FXulong end=file.position(); FXulong size; FXuint size32=0xFFFFFFFF; size=end-8; if (end>0xFFFFFFFF) { // RIFF Chunk file.position(0); file.writeBlock("RF64",4); file.writeBlock(&size32,4); // DS64 Chunk file.position(12); file.writeBlock("ds64",4); file.position(20); file.writeBlock(&size,8); // Data Chunk if (data_pos) { size=end-data_pos-4; file.writeBlock(&size,8); size=0; file.writeBlock(&size,8); } } else { /// RIFF chunksize size32=size; file.position(4); file.writeBlock(&size32,4); // Data Chunksize if (data_pos) { file.position(data_pos); size=end-data_pos-4; file.writeBlock(&size,4); } } file.close(); } af.reset(); }
FXbool HttpClient::open_connection() { GM_DEBUG_PRINT("[http] open_connection()\n"); FXIO * stream = NULL; if (connection==NULL) connection = new ConnectionFactory(); if (options&UseProxy) stream = connection->open(proxy.name.text(),proxy.port); else stream = connection->open(server.name.text(),server.port); if (stream) { io.attach(stream); return true; } return false; }
void ID3V2::parse_text_frame(FXuint frameid,FXint framesize) { FXString text; const FXuchar & encoding = buffer[p]; parse_text(encoding,(const FXchar*)buffer+p+1,framesize-1,text); GM_DEBUG_PRINT("[id3v2] text: \"%s\"\n",text.text()); switch(frameid) { case TP1 : case TPE1 : artist.adopt(text); break; case TAL : case TALB : album.adopt(text); break; case TT2 : case TIT2 : title.adopt(text); break; default : break; } }
long GMNotifyDaemon::onSignal(FXObject*,FXSelector,void*ptr){ DBusMessage * msg = static_cast<DBusMessage*>(ptr); FXuint id,reason; FXchar * action; if (dbus_message_is_signal(msg,GALAGO_NOTIFY_INTERFACE,"NotificationClosed")){ if ((dbus_message_has_signature(msg,"u") && dbus_message_get_args(msg,NULL,DBUS_TYPE_UINT32,&id,DBUS_TYPE_INVALID)) || (dbus_message_has_signature(msg,"uu") && dbus_message_get_args(msg,NULL,DBUS_TYPE_UINT32,&id,DBUS_TYPE_UINT32,&reason,DBUS_TYPE_INVALID))) { if (id==msgid) { msgid=0; } } return 1; } else if (dbus_message_is_signal(msg,GALAGO_NOTIFY_INTERFACE,"ActionInvoked")){ if (dbus_message_has_signature(msg,"us") && dbus_message_get_args(msg,NULL,DBUS_TYPE_UINT32,&id,DBUS_TYPE_STRING,&action,DBUS_TYPE_INVALID)) { if (compare(action,"media-skip-backward")==0) { GMPlayerManager::instance()->cmd_prev(); } else if (compare(action,"media-skip-forward")==0) { GMPlayerManager::instance()->cmd_next(); } else if (compare(action,"media-playback-pause")==0) { GMPlayerManager::instance()->cmd_pause(); } else if (compare(action,"media-playback-start")==0) { GMPlayerManager::instance()->cmd_play(); } else if (compare(action,"media-playback-stop")==0) { GMPlayerManager::instance()->cmd_stop(); } else { GM_DEBUG_PRINT("unhandled action: %s\n",action); } return 1; } } return 0; }
ReadStatus TextReader::process(Packet*packet) { packet->unref(); GM_DEBUG_PRINT("[text] starting read %ld\n",input->size()); if (input->size()>0) { textbuffer.length(input->size()); if (input->read(textbuffer.text(),input->size())!=input->size()) return ReadError; } else { FXint len=0,nread=0; const FXint chunk=4096; do { len+=nread; textbuffer.length(textbuffer.length()+chunk); nread=input->read(&textbuffer[len],chunk); } while(nread>0); textbuffer.trunc(len); if (nread==-1) return ReadError; } return ReadDone; }
FXbool PulseOutput::configure(const AudioFormat & fmt){ const pa_sample_spec * config=nullptr; pa_operation *operation=nullptr; if (!open()) return false; if (stream && fmt==af) return true; if (stream) { pa_stream_disconnect(stream); pa_stream_unref(stream); stream=nullptr; } pa_sample_spec spec; pa_channel_map cmap; if (!to_pulse_format(fmt,spec.format)) goto failed; spec.rate = fmt.rate; spec.channels = fmt.channels; // setup channel map pa_channel_map_init(&cmap); cmap.channels = fmt.channels; for (FXint i=0;i<fmt.channels;i++) { switch(fmt.channeltype(i)) { case Channel::None : cmap.map[i] = PA_CHANNEL_POSITION_INVALID; break; case Channel::Mono : cmap.map[i] = PA_CHANNEL_POSITION_MONO; break; case Channel::FrontLeft : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_LEFT; break; case Channel::FrontRight : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_RIGHT; break; case Channel::FrontCenter : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_CENTER; break; case Channel::BackLeft : cmap.map[i] = PA_CHANNEL_POSITION_REAR_LEFT; break; case Channel::BackRight : cmap.map[i] = PA_CHANNEL_POSITION_REAR_RIGHT; break; case Channel::BackCenter : cmap.map[i] = PA_CHANNEL_POSITION_REAR_CENTER; break; case Channel::SideLeft : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_LEFT; break; case Channel::SideRight : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_RIGHT; break; case Channel::LFE : cmap.map[i] = PA_CHANNEL_POSITION_LFE; break; default: goto failed; } } stream = pa_stream_new(pulse_context,"Goggles Music Manager",&spec,&cmap); if (stream == nullptr) goto failed; #ifdef DEBUG pa_stream_set_state_callback(stream,stream_state_callback,this); #endif //pa_stream_set_write_callback(stream,stream_write_callback,this); if (pa_stream_connect_playback(stream,nullptr,nullptr,PA_STREAM_NOFLAGS,nullptr,nullptr)<0) goto failed; /// Wait until stream is ready pa_stream_state_t state; while((state=pa_stream_get_state(stream))!=PA_STREAM_READY) { if (state==PA_STREAM_FAILED || state==PA_STREAM_TERMINATED){ goto failed; } context->wait_plugin_events(); } /// Get Actual Format config = pa_stream_get_sample_spec(stream); if (!to_gap_format(config->format,af)) goto failed; af.channels=config->channels; af.rate=config->rate; af.channelmap=fmt.channelmap; /// Get Current Volume operation = pa_context_get_sink_input_info(pulse_context,pa_stream_get_index(stream),sink_info_callback,this); if (operation) pa_operation_unref(operation); return true; failed: GM_DEBUG_PRINT("[pulse] Unsupported pulse configuration:\n"); fmt.debug(); return false; }
///FIXME perhaps support extensible wav format FXbool WavOutput::configure(const AudioFormat & fmt) { FXushort format; // Can't handle big endian yet, neither does the output thread handle byteorder swaps if (fmt.byteorder() != Format::Little) return false; // Extensible Wav Format not yet supported if (fmt.channels>2) return false; // Determine format switch(fmt.datatype()) { case Format::Unsigned : case Format::Signed : format = WAV_FORMAT_PCM; break; case Format::Float : format = WAV_FORMAT_FLOAT; break; default : return false; break; } FXString path=FXPath::unique("gap.wav"); if (file.open(path,FXIO::Writing)) { GM_DEBUG_PRINT("[wav] opened output file: %s\n",path.text()); af=fmt; FXuint chunksize=0; FXlong ldata=0; /// riff chunk file.writeBlock("RIFF",4); file.writeBlock(&chunksize,4); // empty for now file.writeBlock("WAVE",4); /// junk chunk chunksize=28; file.writeBlock("JUNK",4); file.writeBlock(&chunksize,4); file.writeBlock(&ldata,8); file.writeBlock(&ldata,8); file.writeBlock(&ldata,8); chunksize=0; file.writeBlock(&chunksize,4); /// fmt file.writeBlock("fmt ",4); chunksize=16; file.writeBlock(&chunksize,4); file.writeBlock(&format,2); FXushort channels=fmt.channels; FXuint rate=fmt.rate; FXuint byterate=fmt.rate*fmt.channels*fmt.packing(); FXushort blockalign=fmt.framesize(); FXushort bitspersample=fmt.bps(); file.writeBlock(&channels,2); file.writeBlock(&rate,4); file.writeBlock(&byterate,4); file.writeBlock(&blockalign,2); file.writeBlock(&bitspersample,2); file.writeBlock("data",4); chunksize=0xFFFFFFFF; data_pos=file.position(); file.writeBlock(&chunksize,4); return true; } GM_DEBUG_PRINT("[wav] failed to open output file: %s\n",path.text()); return false; }
void InputThread::ctrl_flush(FXbool close){ GM_DEBUG_PRINT("[input] flush\n"); engine->decoder->post(new FlushEvent(close),EventQueue::Flush); }
DecoderStatus VorbisDecoder::process(Packet * packet) { FXASSERT(packet); #ifdef HAVE_VORBIS_PLUGIN FXfloat ** pcm=NULL; FXfloat * buf32=NULL; #else // HAVE_TREMOR_PLUGIN FXint ** pcm=NULL; FXshort * buf32=NULL; #endif FXint p,navail=0; FXint ngiven,ntotalsamples,nsamples,sample,c,s; FXbool eos=packet->flags&FLAG_EOS; FXuint id=packet->stream; FXlong len=packet->stream_length; OggDecoder::process(packet); /// Init Decoder if (!has_dsp) { if (!init_decoder()) return DecoderError; if (!has_dsp) return DecoderOk; } /// Find Stream Position if (stream_position==-1 && !find_stream_position()) return DecoderOk; if (out) { navail = out->availableFrames(); } while(get_next_packet()) { if (__unlikely(is_vorbis_header())) { GM_DEBUG_PRINT("[vorbis] unexpected vorbis header found. Resetting decoder\n"); push_back_packet(); reset_decoder(); return DecoderOk; } if (vorbis_synthesis(&block,&op)==0) vorbis_synthesis_blockin(&dsp,&block); while((ngiven=vorbis_synthesis_pcmout(&dsp,&pcm))>0) { if (len>0) FXASSERT(stream_position+ngiven<=len); if (__unlikely(stream_position<stream_decode_offset)) { FXlong offset = FXMIN(ngiven,stream_decode_offset - stream_position); GM_DEBUG_PRINT("[vorbis] stream decode offset %ld. Skipping %ld of %ld \n",stream_decode_offset,offset,stream_decode_offset-stream_position); ngiven-=offset; stream_position+=offset; sample=offset; vorbis_synthesis_read(&dsp,offset); if (ngiven==0) continue; } else { sample=0; } for (ntotalsamples=ngiven;ntotalsamples>0;) { /// Get new buffer if (out==NULL) { out = engine->decoder->get_output_packet(); if (out==NULL) return DecoderInterrupted; out->stream_position=stream_position; out->stream_length=len; out->af=af; navail = out->availableFrames(); } #ifdef HAVE_VORBIS_PLUGIN buf32 = out->flt(); #else // HAVE_TREMOR_PLUGIN buf32 = out->s16(); #endif /// Copy Samples nsamples = FXMIN(ntotalsamples,navail); for (p=0,s=sample;s<(nsamples+sample);s++){ for (c=0;c<info.channels;c++,p++) { #ifdef HAVE_VORBIS_PLUGIN buf32[p]=pcm[c][s]; #else buf32[p]=CLIP_TO_15(pcm[c][s]>>9); #endif } } /// Update sample counts out->wroteFrames(nsamples); sample+=nsamples; navail-=nsamples; ntotalsamples-=nsamples; stream_position+=nsamples; /// Send out packet if full ///FIXME handle EOS. if (navail==0) { engine->output->post(out); out=NULL; } } vorbis_synthesis_read(&dsp,ngiven); } } if (eos) { if (out && out->numFrames()) { engine->output->post(out); out=NULL; } engine->output->post(new ControlEvent(End,id)); } return DecoderOk; }
DecoderStatus AacDecoder::process(Packet*packet){ FXlong fs = packet->stream_position; FXbool eos = packet->flags&FLAG_EOS; long unsigned int samplerate; FXuchar channels; NeAACDecFrameInfo frame; if (packet->flags&AAC_FLAG_CONFIG) { handle = NeAACDecOpen(); if (NeAACDecInit2(handle,packet->data(),packet->size(),&samplerate,&channels)<0){ packet->unref(); return DecoderError; } return DecoderOk; } else { buffer.append(packet->data(),packet->size()); packet->unref(); if (handle==NULL) { handle = NeAACDecOpen(); long n = NeAACDecInit(handle,buffer.data(),buffer.size(),&samplerate,&channels); if (n<0) return DecoderError; else if (n>0) buffer.readBytes(n); af.set(AP_FORMAT_S16,samplerate,channels); engine->output->post(new ConfigureEvent(af,Codec::AAC)); } } if (buffer.size()<FAAD_MIN_STREAMSIZE*2) { return DecoderOk; } do { if (out==NULL){ out = engine->decoder->get_output_packet(); if (out==NULL) return DecoderInterrupted; out->af = af; out->stream_position = fs; out->stream_length = packet->stream_length; } void * outbuffer = out->ptr(); NeAACDecDecode2(handle,&frame,buffer.data(),buffer.size(),&outbuffer,out->availableFrames()*out->af.framesize()); if (frame.bytesconsumed>0) { buffer.readBytes(frame.bytesconsumed); } if (frame.error > 0) { GM_DEBUG_PRINT("[aac] error %d (%ld): %s\n",frame.error,frame.bytesconsumed,faacDecGetErrorMessage(frame.error)); } if (frame.samples) { fs+=(frame.samples/frame.channels); out->wroteFrames((frame.samples/frame.channels)); if (out->availableFrames()==0) { engine->output->post(out); out=NULL; } } } while(buffer.size()>(2*FAAD_MIN_STREAMSIZE) && frame.bytesconsumed); if (eos) { if (out) { engine->output->post(out); out=NULL; } engine->output->post(new ControlEvent(End,packet->stream)); } return DecoderOk; }
FXint InputThread::run(){ Event * event; ap_set_thread_name("ap_input"); for (;;) { if (reader && state==StateProcessing) event = wait_for_packet(); else event = wait_for_event(); switch(event->type) { case Ctrl_Close : ctrl_flush(true); ctrl_close_input(true); break; case Ctrl_Open_Flush: ctrl_flush(); case Ctrl_Open : ctrl_open_input(((ControlEvent*)event)->text); break; case Ctrl_Quit : ctrl_close_input(true); engine->decoder->post(event,EventQueue::Flush); return 0; break; case Ctrl_Seek : ctrl_seek(((CtrlSeekEvent*)event)->pos); break; case End : if (event->stream==streamid) { ctrl_eos(); } break; case Meta : engine->decoder->post(event); continue; break; case AP_EOS : GM_DEBUG_PRINT("[input] eos\n"); if (state!=StateError) { engine->post(event); continue; } break; case Buffer : { Packet * packet = dynamic_cast<Packet*>(event); FXASSERT(reader); FXASSERT(packet); packet->stream = streamid; FXuint status = reader->process(packet); switch(status) { case ReadError : GM_DEBUG_PRINT("[input] error\n"); ctrl_close_input(); set_state(StateError,true); break; case ReadDone : GM_DEBUG_PRINT("[input] done\n"); set_state(StateIdle); break; case ReadRedirect : {GM_DEBUG_PRINT("[input] redirect\n"); FXStringList list; reader->redirect(list); ctrl_open_inputs(list); } break; default : break; } continue; /* packet already released */ break; } } Event::unref(event); } return 0; }