summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaromil <jaromil@949728d9-16ea-0310-a75c-cbdf8430a4b8>2006-10-11 14:51:56 (GMT)
committer jaromil <jaromil@949728d9-16ea-0310-a75c-cbdf8430a4b8>2006-10-11 14:51:56 (GMT)
commit0d0d8732a32d91c57c61f1f816fdb50263dab227 (patch)
treebc1df7b87a3b97dedc92bc3d727ffbe5cbd141b5
parent0b227c4d1e39d7b1d37df2c58656e15123b4affa (diff)
new SyncStart xmlrpc command for remote syncstarting,
soundcard playback modules imported from MuSE git-svn-id: svn://dyne.org/montevideo/ivysync@71 949728d9-16ea-0310-a75c-cbdf8430a4b8
-rw-r--r--branches/lydia/Makefile4
-rw-r--r--branches/lydia/cmdline.cpp1
-rw-r--r--branches/lydia/dec_snd.cpp121
-rw-r--r--branches/lydia/dec_snd.h64
-rw-r--r--branches/lydia/decoder.cpp18
-rw-r--r--branches/lydia/decoder.h4
-rw-r--r--branches/lydia/dev_sound.cpp383
-rw-r--r--branches/lydia/dev_sound.h92
-rwxr-xr-xbranches/lydia/ivysync-remote.py13
-rw-r--r--branches/lydia/xmlrpc.cpp25
-rw-r--r--branches/lydia/xmlrpc.h17
11 files changed, 728 insertions, 14 deletions
diff --git a/branches/lydia/Makefile b/branches/lydia/Makefile
index 8c7e541..a81cdd5 100644
--- a/branches/lydia/Makefile
+++ b/branches/lydia/Makefile
@@ -10,8 +10,6 @@ LINKER = ld
GTKFLAGS = `pkg-config --cflags gtk+-2.0`
GTKLIBS = `pkg-config --libs gtk+-2.0`
-AOFLAGS = `pkg-config --cflags ao`
-AOFLAGS = `pkg-config --libs ao`
# debugging flags:
@@ -32,7 +30,7 @@ xmlrpc:
cd xmlrpc++ && $(MAKE)
ivysync: $(IVYSYNC_OBJ)
- $(CPP) $(CPPFLAGS) -o ivysync $(IVYSYNC_OBJ) $(LIBS) $(GTKLIBS) $(AOLIBS)
+ $(CPP) $(CPPFLAGS) -o ivysync $(IVYSYNC_OBJ) $(LIBS) $(GTKLIBS)
#make clean
clean:
diff --git a/branches/lydia/cmdline.cpp b/branches/lydia/cmdline.cpp
index c73ea80..43d3042 100644
--- a/branches/lydia/cmdline.cpp
+++ b/branches/lydia/cmdline.cpp
@@ -323,6 +323,7 @@ int main(int argc, char **argv) {
new SetOffset(xmlrpc, &decoders);
new Open (xmlrpc, &decoders);
new Quit (xmlrpc, &decoders);
+ new SyncStart (xmlrpc, &decoders);
ivydaemon = new IvySyncDaemon(xmlrpc);
diff --git a/branches/lydia/dec_snd.cpp b/branches/lydia/dec_snd.cpp
new file mode 100644
index 0000000..f856c68
--- /dev/null
+++ b/branches/lydia/dec_snd.cpp
@@ -0,0 +1,121 @@
+/* MuSE - Multiple Streaming Engine
+ * Copyright (C) 2004 Angelo Michele, Failla aka pallotron <pallotron@freaknet.org>
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This source code 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.
+ * Please refer to the GNU Public License for more details.
+ *
+ * You should have received a copy of the GNU Public License along with
+ * this source code; if not, write to:
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+
+#include <dec_snd.h>
+#include <jutils.h>
+#include <config.h>
+
+#ifdef HAVE_SNDFILE
+
+/* ----- LibSndFile input channel ----- */
+
+MuseDecSndFile::MuseDecSndFile ():MuseDec (){
+ func ("MuseDecSndFile::MuseDecSndFile()");
+ strncpy (name, "Snd", 4);
+ memset(&sf_info_struct, 0, sizeof(sf_info_struct));
+}
+
+MuseDecSndFile::~MuseDecSndFile (){
+ func ("MuseDecSndFile::~MuseSndFile()");
+ sf_close (sf);
+}
+
+int MuseDecSndFile::load (char *file) {
+
+ int res;
+ /* 0 => error
+ * 1 => success && seekable
+ * 2 => success && !seekable
+ */
+
+ /* all the info about the audio file into the sf_info_struct struct */
+ if(!(sf = sf_open(file, SFM_READ, &sf_info_struct))) {
+ warning("MuseDecSndFile:_load(): cannot open input file");
+ return (0);
+ }
+ /*
+ * this is sndfile file info structure
+ *
+ * typedef struct
+ * { sf_count_t frames ; // used to be called samples
+ * int samplerate ;
+ * int channels ;
+ * int format ;
+ * int sections ;
+ * int seekable ;
+ * } SF_INFO ;
+ */
+ samplerate = sf_info_struct.samplerate;
+ channels = sf_info_struct.channels;
+ seekable = sf_info_struct.seekable ? true : false;
+
+ func("Opened audio file: samplerate => %d, channels => %d, seekable => %s",
+ samplerate, channels, seekable ? "true" : "false");
+
+ framepos = 0;
+
+ if(seekable) {
+ frametot = sf_info_struct.frames;
+ func("Audio file is seekable: total frames: %d", frametot);
+ res = 1;
+ }
+ else res = 2;
+
+ return (res);
+
+}
+
+IN_DATATYPE *MuseDecSndFile::get_audio () {
+
+ frames = sf_read_short(sf, snd_buffer, IN_CHUNK);
+
+ if(frames!=0) {
+
+ framepos += frames/channels;
+ fps = samplerate;
+ // func("MuseDecSndFile::get_audio => Frames readed: %d/%d", framepos, frametot);
+ return ((IN_DATATYPE *) snd_buffer);
+
+ } else { framepos=0; eos = true; return (NULL); }
+}
+
+bool MuseDecSndFile::seek (float pos) {
+
+ if(pos==0.0) {
+
+ framepos = 0;
+ sf_seek(sf, 0, SEEK_SET);
+ func("MuseDecSndFile::seek => Stop. Return to the begin of the track");
+
+ } else {
+
+ if((framepos = sf_seek(sf, (sf_count_t)(frametot * pos), SEEK_SET))==-1) {
+ func("MuseDecSndFile::seek error"); //,sf_strerror(sf));
+ return false;
+ }
+ func("MuseDecSndFile::seek at position %d/%d", framepos, frametot);
+
+ }
+
+ return true;
+}
+
+#endif /* HAVE SNDFILE */
diff --git a/branches/lydia/dec_snd.h b/branches/lydia/dec_snd.h
new file mode 100644
index 0000000..7359baf
--- /dev/null
+++ b/branches/lydia/dec_snd.h
@@ -0,0 +1,64 @@
+/* MuSE - Multiple Streaming Engine
+ * Copyright (C) 2004 Angelo Michele Failla aka pallotron <pallotron@freaknet.org>
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This source code 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.
+ * Please refer to the GNU Public License for more details.
+ *
+ * You should have received a copy of the GNU Public License along with
+ * this source code; if not, write to:
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/**
+ @file dec_ogg.h libsnd decoder
+ @desc input channel: decoder implemenation
+*/
+
+#ifndef __IN_SND_H__
+#define __IN_SND_H__
+
+#include <config.h>
+
+#ifdef HAVE_SNDFILE
+
+#include <decoder.h>
+
+/* libsndfile inclusion */
+#include <sndfile.h>
+
+/**
+ TODO: commento da scrivere
+ @class MuseDecSndFile
+ @brief SndFile decoder
+*/
+class MuseDecSndFile:public MuseDec
+{
+ private:
+ /* pointer to data */
+ SNDFILE *sf;
+ /* file information struct */
+ SF_INFO sf_info_struct;
+ short snd_buffer[IN_CHUNK];
+
+ public:
+ /* TODO: scrivere il commento per la doc */
+ MuseDecSndFile (); /* constructor */
+ ~MuseDecSndFile (); /* destructor */
+
+ int load (char *file);
+ bool seek (float pos);
+
+ IN_DATATYPE *get_audio ();
+
+};
+
+#endif /* HAVE SNDFILE */
+#endif
diff --git a/branches/lydia/decoder.cpp b/branches/lydia/decoder.cpp
index ae46d9d..570038d 100644
--- a/branches/lydia/decoder.cpp
+++ b/branches/lydia/decoder.cpp
@@ -90,9 +90,14 @@ bool Decoder::init(char *dev) {
bool Decoder::setup(bool *sync, int bufsize) {
+ quit = false;
+
// save the syncstarter flag
syncstart = sync;
-
+
+ // if no buffer size is specified, use old one
+ if(!bufsize) return(true);
+
if(buffo) free(buffo);
buffo = (uint8_t*) calloc( bufsize+1, 1024); // +1 safety bound
@@ -103,7 +108,7 @@ bool Decoder::setup(bool *sync, int bufsize) {
buffo_size = bufsize*1024;
- quit = false;
+
return(true);
@@ -449,12 +454,13 @@ void Decoder::setpos(int pos) {
pos, newfilepos);
}
-off64_t Decoder::getoffset() {
- return filepos;
+int Decoder::getoffset() {
+ return( (int)(filepos / 100000) );
}
-void Decoder::setoffset(off64_t pos) {
- (pos < filesize) ? newfilepos = pos : newfilepos = filesize;
+void Decoder::setoffset(int pos) {
+ off64_t offset = pos * 100000;
+ (offset < filesize) ? newfilepos = offset : newfilepos = filesize;
}
bool Decoder::prepend(char *file) {
diff --git a/branches/lydia/decoder.h b/branches/lydia/decoder.h
index dee8c59..b6b836e 100644
--- a/branches/lydia/decoder.h
+++ b/branches/lydia/decoder.h
@@ -89,8 +89,8 @@ class Decoder : public Thread, public Entry {
int getpos();
void setpos(int pos);
- off64_t getoffset();
- void setoffset(off64_t pos);
+ int getoffset();
+ void setoffset(int pos);
/** state flags for use in the inner loop
the following booleans are changed by asynchronous calls
diff --git a/branches/lydia/dev_sound.cpp b/branches/lydia/dev_sound.cpp
new file mode 100644
index 0000000..8c33d40
--- /dev/null
+++ b/branches/lydia/dev_sound.cpp
@@ -0,0 +1,383 @@
+/* MuSE - Multiple Streaming Engine
+ * SoundDevice class interfacing Portaudio PABLIO library
+ * Copyright (C) 2004-2005 Denis Roio aka jaromil <jaromil@dyne.org>
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This source code 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.
+ * Please refer to the GNU Public License for more details.
+ *
+ * You should have received a copy of the GNU Public License along with
+ * this source code; if not, write to:
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ "$Id: dev_sound.cpp 760 2006-03-16 23:37:40Z xant $"
+
+ */
+
+#include <stdlib.h>
+#include <config.h>
+
+#include <dev_sound.h>
+#include <jutils.h>
+#include <generic.h>
+
+#define PA_SAMPLE_TYPE paFloat32
+#define PA_SAMPLES_PER_FRAME 2
+#define PA_NUM_SECONDS 5
+#define FRAMES_PER_BUFFER (64)
+#define PA_PIPE_SIZE MIX_CHUNK*sizeof(PA_SAMPLE_TYPE)*64
+
+#define INPUT_DEVICE Pa_GetDefaultInputDeviceID()
+#define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID()
+
+
+#ifdef HAVE_JACK
+int dev_jack_process(jack_nframes_t nframes, void *arg) {
+
+ jack_nframes_t opframes;
+ SoundDevice *dev = (SoundDevice*)arg;
+ if(!dev->jack) return 0; // just return
+
+ // take output from pipe and send it to jack
+ dev->jack_out_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer(dev->jack_out_port,nframes);
+ opframes = dev->jack_out_pipe->read
+ (nframes * sizeof(float) * 2 , dev->jack_out_buf);
+
+ // take input from jack and send it in pipe
+ dev->jack_in_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer(dev->jack_in_port,nframes);
+ dev->jack_in_pipe->write // does the float2int conversion in one pass
+ (nframes * sizeof(float) * 2 , dev->jack_in_buf);
+
+ return 0;
+}
+
+void dev_jack_shutdown(void *arg) {
+ SoundDevice *dev = (SoundDevice*)arg;
+ // close the jack channels
+ dev->jack = false;
+ jack_port_unregister(dev->jack_client, dev->jack_in_port);
+ jack_port_unregister(dev->jack_client, dev->jack_out_port);
+ jack_deactivate(dev->jack_client);
+ delete dev->jack_in_pipe;
+ delete dev->jack_out_pipe;
+}
+#endif
+
+
+SoundDevice::SoundDevice() {
+ memset(&input_device,0,sizeof(input_device));
+ memset(&output_device,0,sizeof(output_device));
+ pa_dev.input = &input_device;
+ pa_dev.output = &output_device;
+ input_device.pipe = new Pipe(PA_PIPE_SIZE);
+ input_device.pipe->set_block(false,false);
+ output_device.pipe = new Pipe(PA_PIPE_SIZE);
+ output_device.pipe->set_block(true,false);
+ input_device.pipe->set_output_type("copy_float_to_int16");
+ output_device.pipe->set_input_type("copy_int16_to_float");
+ jack = false;
+ jack_in = false;
+ jack_out = false;
+}
+
+SoundDevice::~SoundDevice() {
+close();
+}
+
+static int pa_process( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+int i,n;
+void *rBuf;
+int readBytes;
+PaDevices *dev = (PaDevices *)userData;
+long len = framesPerBuffer * (PA_SAMPLES_PER_FRAME*sizeof(PA_SAMPLE_TYPE));
+ if(inputBuffer != NULL) { /* handle input from soundcard */
+ if(dev->input->info) {
+ if(dev->input->info->maxInputChannels>1) {
+ readBytes = dev->input->pipe->write(len,inputBuffer);
+ }
+ else {
+ rBuf = malloc(len);
+ n=0;
+ for(i=0;i<(len/sizeof(PA_SAMPLE_TYPE))/2;i++) {
+ ((float *)rBuf)[n]=((float *)inputBuffer)[i];
+ ((float *)rBuf)[n+1]=((float *)inputBuffer)[i];
+ n+=2;
+ }
+ readBytes = dev->input->pipe->write(len,rBuf);
+ free(rBuf);
+ }
+ if(readBytes <= 0) memset(inputBuffer,0,len);
+ }
+ }
+ if(outputBuffer != NULL) { /* handle output to soundcard */
+ if(dev->output->info) {
+ if(dev->output->info->maxOutputChannels>1) {
+ readBytes = dev->output->pipe->read(len,outputBuffer);
+ }
+ else {
+ rBuf = malloc(len);
+ readBytes = dev->output->pipe->read(len,rBuf);
+ n=0;
+ for(i=0;i<(len/sizeof(PA_SAMPLE_TYPE))/2;i++) {
+ ((float *)outputBuffer)[n]=((float *)rBuf)[i];
+ ((float *)outputBuffer)[n+1]=((float *)rBuf)[i];
+ n+=2;
+ }
+ free(rBuf);
+ }
+ if(readBytes <= 0) memset(outputBuffer,0,len);
+ }
+ }
+ return 0;
+}
+
+bool SoundDevice::input(bool state) {
+ bool res = false;
+ if(jack) return true;
+ if(!res) res = pa_open(state,PaInput);
+ return res;
+}
+
+PaError SoundDevice::pa_real_open(int mode) {
+ return Pa_OpenStream( ((mode & PaInput) == PaInput)?&input_device.stream:&output_device.stream,
+ ((mode & PaInput) == PaInput)?input_device.id:paNoDevice,
+ ((mode & PaInput) == PaInput)?(input_device.info->maxInputChannels>1?2:1):0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ ((mode & PaOutput) == PaOutput)?output_device.id:paNoDevice,
+ ((mode & PaOutput) == PaOutput)?(output_device.info->maxOutputChannels>1?2:1):0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, /* number of buffers, if zero then use default minimum */
+ 0, // paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ pa_process,
+ &pa_dev );
+}
+
+bool SoundDevice::pa_open(bool state,int mode) {
+ PaDevInfo *dev,*other;
+ int creq,oreq;
+ char dir[7];
+
+ // PaDeviceInfo *k=NULL;
+ // int i=0;
+ // do {
+// k=Pa_GetDeviceInfo(i);
+// i++;
+/// if(k) printf("KKK %d - %s \n",i,k->name);
+// } while (k!=NULL);
+
+ if(mode == PaInput) { // input requested
+ dev = &input_device;
+ other = &output_device;
+ creq = PaInput;
+ oreq = PaOutput;
+ strcpy(dir,"input");
+ dev->id = Pa_GetDefaultInputDeviceID();
+ }
+ else if(mode == PaOutput) { // output requested
+ dev = &output_device;
+ other = &input_device;
+ creq = PaOutput;
+ oreq = PaInput;
+ strcpy(dir,"output");
+ dev->id = Pa_GetDefaultOutputDeviceID();
+ }
+ if(state && ((pa_mode & creq) != creq)) {
+ dev->info = (PaDeviceInfo*)Pa_GetDeviceInfo( dev->id );
+ if(dev->info) notice("Opening %s device: %s",dir,dev->info->name);
+ else {
+ error("%s device not available",dir);
+ return false;
+ }
+ if((pa_mode & oreq) == oreq) {
+ /* input device is already opened...check if we are trying to open the same device */
+ if(other->info) {
+ Pa_StopStream( other->stream );
+ Pa_CloseStream( other->stream );
+ err = pa_real_open(PaInput|PaOutput);
+ if(err == paNoError ) output_device.stream = input_device.stream;
+ }
+ else {
+ error("Full duplex has been requested but we don't have portaudio information");
+ return false;
+ }
+ }
+ else {
+ err = pa_real_open(mode);
+ }
+ if( err != paNoError) {
+ Pa_Terminate();
+ error("error opening %s sound device: %s",dir,Pa_GetErrorText( err ) );
+ return false;
+ }
+ else {
+ err = Pa_StartStream(dev->stream);
+ if(err != paNoError) {
+ error("error starting %s audio stream: %s",dir,Pa_GetErrorText( err ) );
+ return false;
+ }
+ pa_mode = pa_mode | creq;
+ }
+ } else if(!state && dev->stream) { // XXX - i have to check if this is still right
+ if(dev->info) notice("Closing %s device: %s",dir,dev->info->name);
+ if((pa_mode & creq) == creq) {
+ if((pa_mode & oreq) == oreq) {
+ pa_mode = oreq;
+ }
+ else {
+ Pa_StopStream(dev->stream);
+ Pa_CloseStream(dev->stream);
+ pa_mode = PaNull;
+ }
+ }
+ dev->stream = NULL;
+ dev->info = NULL;
+ dev->pipe->flush();
+ //delete dev->pipe;
+ }
+ return true;
+}
+
+bool SoundDevice::output(bool state) {
+ bool res = false;
+ if(jack) return true;
+ if(!res) res = pa_open(state,PaOutput);
+ return res;
+}
+
+bool SoundDevice::open(bool read, bool write) {
+
+ // notice("detecting sound device");
+
+#ifdef HAVE_JACK
+ // we try to open up a jack client
+ jack_sample_size = sizeof(jack_default_audio_sample_t);
+ if(!jack) // check if it is not allready on
+ if( (jack_client = jack_client_new("MuSE")) !=0 ) {
+ notice("jack audio daemon detected");
+ act("hooking in/out sound channels");
+ warning("this feature is still experimental and won't work!");
+ warning("you need to stop jack and free the audio card");
+ jack = true;
+ jack_samplerate = jack_get_sample_rate(jack_client);
+ jack_set_process_callback(jack_client, dev_jack_process, this);
+ jack_on_shutdown(jack_client,dev_jack_shutdown,this);
+
+ jack_in_pipe = new Pipe();
+ jack_in_pipe->set_output_type("copy_float_to_int16");
+ jack_in_pipe->set_block(false,true);
+
+ jack_out_pipe = new Pipe();
+ jack_out_pipe->set_input_type("copy_int16_to_float");
+ jack_in_pipe->set_block(true,false);
+
+ // open the jack input channel
+ jack_in_port = jack_port_register(jack_client, "capture",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput, 0);
+ // open the jack output channel
+ jack_out_port = jack_port_register(jack_client, "playback",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+
+ jack_activate(jack_client);
+ return true;
+ }
+#endif
+ if( ! output(write) ) return false;
+
+ //if( ! input(read) ) return false;
+
+ return true;
+}
+
+void SoundDevice::close() {
+ if((pa_mode&PaInput) == PaInput) {
+ if((pa_mode&PaOutput) == PaOutput) {
+ pa_mode = PaOutput;
+ if(output_device.stream == input_device.stream)
+ output_device.stream = NULL;
+ }
+ else pa_mode = PaNull;
+ if(input_device.stream) {
+ Pa_StopStream( input_device.stream);
+ Pa_CloseStream( input_device.stream );
+ input_device.stream = NULL;
+ }
+ input_device.pipe->flush();
+ //delete input_device.pipe;
+ }
+
+ if((pa_mode&PaOutput) == PaOutput) {
+ if(output_device.stream) {
+ Pa_StopStream( output_device.stream);
+ Pa_CloseStream( output_device.stream );
+ output_device.stream = NULL;
+ }
+ output_device.pipe->flush();
+ if((pa_mode&PaInput) == PaInput)
+ pa_mode = PaInput;
+ else pa_mode = PaNull;
+ }
+ //delete output_device.pipe;
+}
+
+int SoundDevice::read(void *buf, int len) {
+ // len is in samples: 4*2 32bit stereo
+ int res = -1;
+
+ if(jack) {
+
+ res = jack_in_pipe->read(len*2,buf);
+
+ } else if(input_device.stream) { // portaudio
+
+ // takes number of left and right frames (stereo / 2)
+ res = input_device.pipe->read(len*2,buf);
+ }
+ return res;
+}
+
+int SoundDevice::write(void *buf, int len) {
+ // len is in samples, for bytes must *2 (16bit)
+ int res = -1;
+
+ if(jack) { // jack audio daemon
+
+ res = jack_out_pipe->write(len*2,buf);
+
+ } else if(output_device.stream) { // portaudio
+ res = output_device.pipe->write(len,buf);
+ //func("dspout available pipe space: %d \n",output_device.pipe->space());
+ }
+ return res;
+}
+
+void SoundDevice::flush_output() {
+ if(jack)
+ jack_out_pipe->flush();
+ else if(output_device.stream) { // portaudio
+ output_device.pipe->flush();
+ }
+}
+void SoundDevice::flush_input() {
+ if(jack)
+ jack_in_pipe->flush();
+ else if(input_device.stream) {
+ input_device.pipe->flush();
+ }
+}
diff --git a/branches/lydia/dev_sound.h b/branches/lydia/dev_sound.h
new file mode 100644
index 0000000..c2480f1
--- /dev/null
+++ b/branches/lydia/dev_sound.h
@@ -0,0 +1,92 @@
+#ifndef __DEV_SOUND_H__
+#define __DEV_SOUND_H__
+
+#include <config.h>
+
+#ifdef HAVE_JACK
+#include <jack/jack.h>
+#endif
+
+//#ifdef HAVE_PORTAUDIO
+#include <portaudio.h>
+//#endif
+
+#include <pipe.h>
+
+typedef struct {
+ PaDeviceID id;
+ PortAudioStream *stream;
+ PaDeviceInfo *info;
+ Pipe *pipe;
+} PaDevInfo;
+
+typedef struct {
+ PaDevInfo *input;
+ PaDevInfo *output;
+} PaDevices;
+///< the PortAudio device descriptor , this struct just group some data used by PortAudio framework
+
+class SoundDevice {
+ public:
+ SoundDevice();
+ ///< the SoundDevice class constructor
+ ~SoundDevice();
+ ///< the SoundDevice class destructor
+
+ /**
+ Tries to open the sound device for read and/or write
+ if full-duplex is requested but not supported, it returns error
+ and must be called again to fallback on half-duplex mode
+
+ @param read true if device is opened for reading audio
+ @param write true if device is opened for writing audio
+ @return true in case of success, false otherwise
+ */
+ bool open(bool read, bool write);
+ ///< open the sound device
+
+ bool input(bool state); ///< activate sound input
+ bool output(bool state); ///< activate sound output
+
+ void close(); ///< close the sound device
+
+ int read(void *buf, int len); ///< reads audio data from the device in a buffer, len is samples
+
+ int write(void *buf, int len); ///< writes audio data from a buffer to the device, len is samples
+ void flush_input();
+ void flush_output();
+
+ bool jack;
+ bool jack_in;
+ bool jack_out;
+
+ /* TODO - should be private */
+ PaDevInfo input_device; ///< portaudio input device
+ PaDevInfo output_device; ///< portaudio output device
+ private:
+ bool pa_open(bool state,int mode);
+ PaError pa_real_open(int mode);
+
+ PaError err;
+
+ PaDevices pa_dev;
+ int pa_mode; ///< a switch to represent portaudio mode currently using (for noaudio,input,output or both)
+#define PaNull 0
+#define PaInput 1
+#define PaOutput 2
+
+ Pipe *jack_in_pipe;
+ Pipe *jack_out_pipe;
+#ifdef HAVE_JACK
+ jack_client_t *jack_client;
+ jack_port_t *jack_in_port;
+ jack_port_t *jack_out_port;
+ jack_default_audio_sample_t *jack_in_buf;
+ jack_default_audio_sample_t *jack_out_buf;
+ size_t jack_sample_size;
+ int jack_samplerate;
+#endif
+
+};
+
+#endif
diff --git a/branches/lydia/ivysync-remote.py b/branches/lydia/ivysync-remote.py
index df0c2c6..6523e44 100755
--- a/branches/lydia/ivysync-remote.py
+++ b/branches/lydia/ivysync-remote.py
@@ -53,7 +53,7 @@ class xmlrpc_connection:
if __name__ == '__main__':
- commands = ("Play", "Stop", "Open", "Pause", "Quit", "GetPos", "SetPos", "GetOffset", "SetOffset")
+ commands = ("Play", "SyncStart", "Stop", "Open", "Pause", "Quit", "GetPos", "SetPos", "GetOffset", "SetOffset")
connection = xmlrpc_connection()
@@ -68,9 +68,16 @@ if __name__ == '__main__':
print "no valid command recognized, list of valid commands:"
print commands
sys.exit(2)
-
+
+ if cmd == "SyncStart":
+ (res,) = connection.remote(cmd, (0, 0))
+ if res == 1:
+ answer = "Sync starting OK"
+ else:
+ answer = "Error in sync starting"
+
- if cmd == "Quit":
+ elif cmd == "Quit":
(res,) = connection.remote(cmd, (0, 0))
if res == 1:
diff --git a/branches/lydia/xmlrpc.cpp b/branches/lydia/xmlrpc.cpp
index 8386607..8e5fd75 100644
--- a/branches/lydia/xmlrpc.cpp
+++ b/branches/lydia/xmlrpc.cpp
@@ -65,6 +65,11 @@ Play::Play(XmlRpcServer* srv, Linklist *decoders)
IvySyncPublicMethod(decoders)
{ }
+SyncStart::SyncStart(XmlRpcServer* srv, Linklist *decoders)
+ : XmlRpcServerMethod("SyncStart", srv),
+ IvySyncPublicMethod(decoders)
+{ }
+
Stop::Stop(XmlRpcServer* srv, Linklist *decoders)
: XmlRpcServerMethod("Stop", srv),
IvySyncPublicMethod(decoders)
@@ -178,7 +183,27 @@ void Play::execute(XmlRpcValue &params, XmlRpcValue &result) {
result = (double) dec->play();
}
+void SyncStart::execute(XmlRpcValue &params, XmlRpcValue &result) {
+
+ D("syncstart called");
+ Decoder *dec = (Decoder*) decoders->begin();
+
+ while(dec) {
+ dec->stop();
+ dec->setup(&syncer, 0);
+ dec->play();
+ dec = (Decoder*) dec->next;
+ }
+
+ N("synced start in 3 seconds...");
+ jsleep(3,0);
+
+ syncer = true;
+
+ result = 1.0;
+ A("...start!");
+}
void Stop::execute(XmlRpcValue &params, XmlRpcValue &result) {
int decnum;
diff --git a/branches/lydia/xmlrpc.h b/branches/lydia/xmlrpc.h
index 0dfab27..ec30a63 100644
--- a/branches/lydia/xmlrpc.h
+++ b/branches/lydia/xmlrpc.h
@@ -93,6 +93,23 @@ public:
};
+class SyncStart : public XmlRpcServerMethod, IvySyncPublicMethod {
+public:
+
+ SyncStart(XmlRpcServer* srv, Linklist *decoders);
+
+ ~SyncStart() { };
+
+ void execute(XmlRpcValue &params, XmlRpcValue &result);
+
+ std::string help() {
+ return std::string("Start playing all channels in sync"); }
+
+ private:
+ bool syncer;
+
+};
+
class Stop : public XmlRpcServerMethod, IvySyncPublicMethod {
public: