[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-multimedia
Subject:    recording stream
From:       Matthias Kretz <Matthias () Kretz ! dyndns ! org>
Date:       2001-10-21 19:29:56
[Download RAW message or body]

I finally got recording from aRts working. I did a lot of stuff so let me sum 
up:

- A play stream works using the ByteSoundProducer interface. Therefor I 
created a ByteSoundReceiver.

- Now the ByteSoundProducer was attached to the soundserver using 
SimpleSoundServer->attach(ByteSoundProducer). To make it usable for me I 
created another interface ByteSoundStream that is used for both the 
ByteSoundProducer and ByteSoundReceiver. So I changed the method to 
SimpleSoundServer->attach(ByteSoundStream). This is, of course, not binary 
compatible. I don't know about wire compatibility (I only know that noatun 
1.2.0 (KDE 2.2) still works).
Uhmm, while testing for WC I found out that artscat and artsdsp (from KDE 
2.2) won't work with my changes. But it works if I don't use the 
ByteSoundStream interface but simply SynthModule. So the method would be 
SimpleSoundServer->attach(SynthModule). I guess this is the better way, and 
probably the more flexible, too. If I'm right WC will be preserved this way.

- RecordStreamJob: The same as the PlaySreamJob, only using an 
AudioToByteStream instead of ByteToAudioStream.

- artsdump: The same as artscat for dumping a ByteStream from aRts to a file 
or stdout.

- The AudioToByteStream interface was another hurdle on the way. If I read 
the code correctly the Resampler isn't able to convert from an aRts input to 
a bytestream, and also can't be fitted to do that easily. So I wrote my own 
resampler in this class. I'm not sure whether this is the right way to go and 
I'm open for better ideas.

- Finally I worked on the artsc interface to support the new recording 
capabilities.
In artscbackend.cc there was one class Sender that would create the 
bytestream. I copied this to a new class Stream that holds everything a 
Receiver needs as well. Receiver and Sender inherit from Stream. Now the only 
problem were the ArtsCApi methods that would have to be able to call methods 
of Sender as well as of Receiver while they only receive a void*. I tried to 
cast like this:

int stream_set(arts_stream_t stream, arts_parameter_t param, int value)
{
  SynthModule *_stream = (SynthModule *)stream;
  if( _stream->_interfaceName() == "Arts::ByteStreamProducer" )

But the program would just crash in _stream->_interfaceName() because 
somewhere a dangling pointer, that should be pointing to the base class, was 
being used. So I tried something else:

int stream_set(arts_stream_t stream, arts_parameter_t param, int value)
{
  Stream *_stream = (Stream *)stream;
  if( _stream->direction() == Stream::RECORDSTREAM )

But now _stream would somehow (I have no clue, but gdb said so) be 0x0 when 
_stream->direction() gets called. I finally got it working by doing the 
following:

int stream_set(arts_stream_t stream, arts_parameter_t param, int value)
{
  Sender *_stream = (Sender *)stream;
  _stream->stream_set(param,value);
}

That works even if stream is a Receiver. I have a bad feeling about this, but 
this is the only way I found to get it working.

I'll commit next Friday if nobody objects.

-- 
C'ya
        Matthias
________________________________________________________
Matthias Kretz (Germany)
http://Kretz.dyndns.org/
MatthiasKretz@gmx.net, kretz@kde.org



["artsrecording.patch" (text/x-diff)]

Index: artsc/artscbackend.cc
===================================================================
RCS file: /home/kde/kdelibs/arts/artsc/artscbackend.cc,v
retrieving revision 1.15
diff -u -3 -p -r1.15 artscbackend.cc
--- artsc/artscbackend.cc	2001/01/17 15:21:26	1.15
+++ artsc/artscbackend.cc	2001/10/21 19:14:57
@@ -40,34 +40,27 @@ using namespace std;
 using namespace Arts;
 
 
-class Sender :	public ByteSoundProducer_skel,
-				public StdSynthModule
+class Stream
 {
-	SoundServer server;
-	float serverBufferTime;
-
-	/*
-	 * FIXME: bsWrapper is a more or less ugly trick to be able to use
-	 * this object although not using smartwrappers to access it
-	 */
-	ByteSoundProducer bsWrapper;
+protected:
+	SoundServer m_server;
+	float m_serverBufferTime;
 
-	bool _finished, isAttached;
-	int _samplingRate, _bits, _channels, pos;
-	string _name;
-	queue< DataPacket<mcopbyte>* > outqueue;
+	bool m_finished, m_isAttached;
+	int m_samplingRate, m_bits, m_channels, m_pos;
+	string m_name;
+	queue< DataPacket<mcopbyte>* > m_queue;
 
-	int packetCount, packetCapacity;
-	int blockingIO;
+	int m_packetCount, m_packetCapacity;
+	int m_blockingIO;
 
-protected:
 	/**
 	 * returns the amount of bytes that will be played in a given amount of
 	 * time in milliseconds
 	 */
 	int timeToBytes(float time)
 	{
-    	float playSpeed = channels() * samplingRate() * bits() / 8;
+    	float playSpeed = m_channels * m_samplingRate * m_bits / 8;
 		return (int)(playSpeed * (time / 1000.0));
 	}
 
@@ -77,12 +70,12 @@ protected:
 	 */
 	float bytesToTime(int size)
 	{
-    	float playSpeed = channels() * samplingRate() * bits() / 8;
+    	float playSpeed = m_channels * m_samplingRate * m_bits / 8;
 		return (1000.0 * ((float)size) / playSpeed);
 	}
 
 	int bufferSize() {
-		return packetCount * packetCapacity;
+		return m_packetCount * m_packetCapacity;
 	}
 
 	float bufferTime() {
@@ -97,12 +90,12 @@ protected:
 		/* make sure that our information is up-to-date */
 		Dispatcher::the()->ioManager()->processOneEvent(false);
 
-		if(!outqueue.empty())
+		if(!m_queue.empty())
 		{
-			space += packetCapacity - pos;  /* the first, half filled packet */
+			space += m_packetCapacity - m_pos;  /* the first, half filled packet */
 
-			if(outqueue.size() > 1)			/* and the other, empty packets */
-				space += (outqueue.size()-1)*packetCapacity;
+			if(m_queue.size() > 1)			/* and the other, empty packets */
+				space += (m_queue.size()-1)*m_packetCapacity;
 		}
 		return space;
 	}
@@ -110,7 +103,7 @@ protected:
 	int setBufferSize(int size)
 	{
 		/* don't change sizes when already streaming */
-		if(isAttached)
+		if(m_isAttached)
 			return ARTS_E_NOIMPL;
 
 		/*
@@ -119,8 +112,8 @@ protected:
 		 * this is possible - for now, don't request the impossible or don't
 		 * complain if it doesn't work
 		 */
-		packetCount = 3;
-		packetCapacity = 128;
+		m_packetCount = 3;
+		m_packetCapacity = 128;
 
 		/*
 		 * - do not configure stream buffers smaller than the server
@@ -128,15 +121,15 @@ protected:
 		 * - try to get more or less close to the value the application
 		 *   wants
 		 */
-		int needSize = max(size, timeToBytes(server.minStreamBufferTime()));
+		int needSize = max(size, timeToBytes(m_server.minStreamBufferTime()));
 
 		while(bufferSize() < needSize)
 		{
-			packetCount++;
-			if(packetCount == 8)
+			m_packetCount++;
+			if(m_packetCount == 8)
 			{
-				packetCount /= 2;
-				packetCapacity *= 2;
+				m_packetCount /= 2;
+				m_packetCapacity *= 2;
 			}
 		}
 
@@ -147,29 +140,29 @@ protected:
 	{
 		int settings = 0;
 
-		int cap = packetCapacity;
+		int cap = m_packetCapacity;
 		while(cap > 1)
 		{
 			settings++;
 			cap /= 2;
 		}
 
-		settings |= packetCount << 16;
+		settings |= m_packetCount << 16;
 		return settings;
 	}
 
 	int setPacketSettings(int settings)
 	{
 		/* don't change sizes when already streaming */
-		if(isAttached)
+		if(m_isAttached)
 			return ARTS_E_NOIMPL;
 
-		packetCount = settings >> 16;
+		m_packetCount = settings >> 16;
 		
-		packetCapacity = 1;
+		m_packetCapacity = 1;
 		int c = settings & 0xffff;
 		while(c > 0) {
-			packetCapacity *= 2;
+			m_packetCapacity *= 2;
 			c--;
 		}
 
@@ -178,59 +171,36 @@ protected:
 		 *   recommended value
 		 * - keep the packetSize the applications specified
 		 */
-		int needSize = timeToBytes(server.minStreamBufferTime());
+		int needSize = timeToBytes(m_server.minStreamBufferTime());
 
 		while(bufferSize() < needSize)
-			packetCount++;
+			m_packetCount++;
 
 		return packetSettings();
 	}
 
-
-	void attach()
-	{
-		if(!isAttached)
-		{
-			isAttached = true;
 
-			server.attach(bsWrapper);
-			start();
-
-            /*
-             * TODO: this processOneEvent looks a bit strange here... it is
-             * there since StdIOManager does block 5 seconds on the first
-             * arts_write if it isn't - although notifications are pending
-             *
-             * Probably the real solution is to rewrite the
-             * StdIOManager::processOneEvent function. (And maybe drop the
-             * assumption that aRts will not block when an infinite amount
-             * of notifications is pending - I mean: will it ever happen?)
-             */
-            Dispatcher::the()->ioManager()->processOneEvent(false);
-		}
-	}
+	virtual void attach() = 0;
 
 public:
-	Sender(SoundServer server, int rate, int bits, int channels,
-		string name) : server(server), _finished(false), isAttached(false),
-		_samplingRate(rate), _bits(bits), _channels(channels), pos(0),
-		_name(name)
+	Stream(SoundServer server, int rate, int bits, int channels,
+		string name) : m_server(server), m_finished(false), m_isAttached(false),
+		m_samplingRate(rate), m_bits(bits), m_channels(channels), m_pos(0),
+		m_name(name)
 	{
-		serverBufferTime = server.serverBufferTime();
+		m_serverBufferTime = m_server.serverBufferTime();
 		stream_set(ARTS_P_BUFFER_SIZE,64*1024);
 		stream_set(ARTS_P_BLOCKING,1);
-		bsWrapper = ByteSoundProducer::_from_base(this);
+		//bsWrapper = ByteSoundProducer::_from_base(this);
 	}
-	~Sender()
+	virtual ~Stream()
 	{
 		//
 	}
-	long samplingRate() { return _samplingRate; }
-	long channels()     { return _channels; }
-	long bits()         { return _bits; }
-	bool finished()     { return _finished; }
+
+	enum StreamDirection { PLAYSTREAM, RECORDSTREAM };
 
-	int stream_set(arts_parameter_t param, int value)
+	virtual int stream_set(arts_parameter_t param, int value)
 	{
 		int result;
 
@@ -249,8 +219,8 @@ public:
 			case ARTS_P_BLOCKING:
 				if(value != 0 && value != 1) return ARTS_E_NOIMPL;
 
-				blockingIO = value;
-				return blockingIO;
+				m_blockingIO = value;
+				return m_blockingIO;
 			/*
 			 * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the
 			 * others are of course useless
@@ -265,7 +235,7 @@ public:
 		return ARTS_E_NOIMPL;
 	}
 
-	int stream_get(arts_parameter_t param)
+	virtual int stream_get(arts_parameter_t param)
 	{
 		switch(param) {
 			case ARTS_P_BUFFER_SIZE:
@@ -281,75 +251,247 @@ public:
 				return packetSettings();
 
 			case ARTS_P_SERVER_LATENCY:
-				return (int)serverBufferTime;
+				return (int)m_serverBufferTime;
 
 			case ARTS_P_TOTAL_LATENCY:
 				return stream_get(ARTS_P_SERVER_LATENCY)
 				     + stream_get(ARTS_P_BUFFER_TIME);
 
 			case ARTS_P_BLOCKING:
-				return blockingIO;
+				return m_blockingIO;
 
 			case ARTS_P_PACKET_SIZE:
-				return packetCapacity;
+				return m_packetCapacity;
 
 			case ARTS_P_PACKET_COUNT:
-				return packetCount;
+				return m_packetCount;
 		}
 		return ARTS_E_NOIMPL;
 	}
 
+	int suspend()
+	{
+		if(m_isAttached)
+		{
+			return m_server.suspend();
+		}
+		return 0;
+	}
+};
+
+class Receiver :	public ByteSoundReceiver_skel,
+					public StdSynthModule,
+					public Stream
+{
+	/*
+	 * FIXME: bsWrapper is a more or less ugly trick to be able to use
+	 * this object although not using smartwrappers to access it
+	 */
+	ByteSoundReceiver m_bsWrapper;
+
+protected:
+	virtual void attach()
+	{
+		if(!m_isAttached)
+		{
+			m_isAttached = true;
+
+			m_server.attach(m_bsWrapper);
+			start();
+
+            /*
+             * TODO: this processOneEvent looks a bit strange here... it is
+             * there since StdIOManager does block 5 seconds on the first
+             * arts_write if it isn't - although notifications are pending
+             *
+             * Probably the real solution is to rewrite the
+             * StdIOManager::processOneEvent function. (And maybe drop the
+             * assumption that aRts will not block when an infinite amount
+             * of notifications is pending - I mean: will it ever happen?)
+             */
+            Dispatcher::the()->ioManager()->processOneEvent(false);
+		}
+	}
+
+public:
+	Receiver(SoundServer server, int rate, int bits, int channels,
+		string name) : Stream( server, rate, bits, channels, name)
+	{
+		m_bsWrapper = ByteSoundReceiver::_from_base(this);
+	}
+
+	virtual ~Receiver() {
+		//
+	}
+
+	long samplingRate() { return m_samplingRate; }
+	long channels()     { return m_channels; }
+	long bits()         { return m_bits; }
+	bool finished()     { return m_finished; }
+
+	void process_indata(DataPacket<mcopbyte> *packet)
+	{
+		m_queue.push(packet);
+	}
+
+	void close()
+	{
+		if(m_isAttached)
+		{
+			/* remove all packets from the m_queue */
+			while(!m_queue.empty())
+			{
+				DataPacket<mcopbyte> *packet = m_queue.front();
+				packet->processed();
+				m_queue.pop();
+			}
+
+			m_server.detach(m_bsWrapper);
+		}
+		// similar effect like "delete this;"		
+		m_bsWrapper = ByteSoundReceiver::null();
+	}
+
+	int read(mcopbyte *data, int size)
+	{
+		attach();
+
+		int remaining = size;
+		while(remaining)
+		{
+			if(m_blockingIO)
+			{
+				/* C API blocking style write */
+				while(m_queue.empty())
+					Dispatcher::the()->ioManager()->processOneEvent(true);
+			}
+			else
+			{
+				/* non blocking I/O */
+				if(m_queue.empty())
+					Dispatcher::the()->ioManager()->processOneEvent(false);
+
+				/* still no more space to write? */
+				if(m_queue.empty())
+					return size - remaining;
+			}
+
+			/* get a packet */
+			DataPacket<mcopbyte> *packet = m_queue.front();
+
+			/* copy some data there */
+			int tocopy = min(remaining,packet->size-m_pos);
+			memcpy(data,&packet->contents[m_pos],tocopy);
+			m_pos += tocopy;
+			data += tocopy;
+			remaining -= tocopy;
+
+			/* have we filled up the packet? then send it */
+			if(m_pos == packet->size)
+			{
+				packet->processed();
+				m_queue.pop();
+				m_pos = 0;
+			}
+		}
+
+		/* no possible error conditions */
+		return size;
+	}
+};
+
+class Sender :	public ByteSoundProducer_skel,
+				public StdSynthModule,
+				public Stream
+{
+	/*
+	 * FIXME: bsWrapper is a more or less ugly trick to be able to use
+	 * this object although not using smartwrappers to access it
+	 */
+	ByteSoundProducer m_bsWrapper;
+
+protected:
+	virtual void attach()
+	{
+		if(!m_isAttached)
+		{
+			m_isAttached = true;
+
+			m_server.attach(m_bsWrapper);
+			start();
+
+            /*
+             * TODO: this processOneEvent looks a bit strange here... it is
+             * there since StdIOManager does block 5 seconds on the first
+             * arts_write if it isn't - although notifications are pending
+             *
+             * Probably the real solution is to rewrite the
+             * StdIOManager::processOneEvent function. (And maybe drop the
+             * assumption that aRts will not block when an infinite amount
+             * of notifications is pending - I mean: will it ever happen?)
+             */
+            Dispatcher::the()->ioManager()->processOneEvent(false);
+		}
+	}
+
+public:
+	Sender(SoundServer server, int rate, int bits, int channels,
+		string name) : Stream( server, rate, bits, channels, name)
+	{
+		m_bsWrapper = ByteSoundProducer::_from_base(this);
+	}
+
+	virtual ~Sender() {
+		//
+	}
+
+	long samplingRate() { return m_samplingRate; }
+	long channels()     { return m_channels; }
+	long bits()         { return m_bits; }
+	bool finished()     { return m_finished; }
+
 	void streamStart()
 	{
 		/*
 		 * start streaming
 		 */
-		outdata.setPull(packetCount, packetCapacity);
+		outdata.setPull(m_packetCount, m_packetCapacity);
 	}
 
 	void request_outdata(DataPacket<mcopbyte> *packet)
 	{
-		outqueue.push(packet);
+		m_queue.push(packet);
 	}
 
 	void close()
 	{
-		if(isAttached)
+		if(m_isAttached)
 		{
-			if(pos != 0)
+			if(m_pos != 0)
 			{
 				/* send the last half-filled packet */
-				DataPacket<mcopbyte> *packet = outqueue.front();
-				packet->size = pos;
+				DataPacket<mcopbyte> *packet = m_queue.front();
+				packet->size = m_pos;
 				packet->send();
-				outqueue.pop();
+				m_queue.pop();
 			}
 			outdata.endPull();
 
-			/* remove all packets from the outqueue */
-			while(!outqueue.empty())
+			/* remove all packets from the m_queue */
+			while(!m_queue.empty())
 			{
-				DataPacket<mcopbyte> *packet = outqueue.front();
+				DataPacket<mcopbyte> *packet = m_queue.front();
 				packet->size = 0;
 				packet->send();
-				outqueue.pop();
+				m_queue.pop();
 			}
 
-			server.detach(bsWrapper);
+			m_server.detach(m_bsWrapper);
 		}
 		// similar effect like "delete this;"		
-		bsWrapper = ByteSoundProducer::null();
+		m_bsWrapper = ByteSoundProducer::null();
 	}
 
-	int suspend()
-	{
-		if(isAttached)
-		{
-			return server.suspend();
-		}
-		return 0;
-	}
-
 	int write(const mcopbyte *data, int size)
 	{
 		attach();
@@ -357,40 +499,40 @@ public:
 		int remaining = size;
 		while(remaining)
 		{
-			if(blockingIO)
+			if(m_blockingIO)
 			{
 				/* C API blocking style write */
-				while(outqueue.empty())
+				while(m_queue.empty())
 					Dispatcher::the()->ioManager()->processOneEvent(true);
 			}
 			else
 			{
 				/* non blocking I/O */
-				if(outqueue.empty())
+				if(m_queue.empty())
 					Dispatcher::the()->ioManager()->processOneEvent(false);
 
 				/* still no more space to write? */
-				if(outqueue.empty())
+				if(m_queue.empty())
 					return size - remaining;
 			}
 
 			/* get a packet */
-			DataPacket<mcopbyte> *packet = outqueue.front();
+			DataPacket<mcopbyte> *packet = m_queue.front();
 
 			/* copy some data there */
-			int tocopy = min(remaining,packetCapacity-pos);
-			memcpy(&packet->contents[pos],data,tocopy);
-			pos += tocopy;
+			int tocopy = min(remaining,m_packetCapacity-m_pos);
+			memcpy(&packet->contents[m_pos],data,tocopy);
+			m_pos += tocopy;
 			data += tocopy;
 			remaining -= tocopy;
 
 			/* have we filled up the packet? then send it */
-			if(pos == packetCapacity)
+			if(m_pos == m_packetCapacity)
 			{
-				packet->size = packetCapacity;
+				packet->size = m_packetCapacity;
 				packet->send();
-				outqueue.pop();
-				pos = 0;
+				m_queue.pop();
+				m_pos = 0;
 			}
 		}
 
@@ -439,15 +581,24 @@ public:
 		return (arts_stream_t)new Sender(server,rate,bits,channels,name);
 	}
 
+	arts_stream_t record_stream(int rate, int bits, int channels, const char *name)
+	{
+		if(server.isNull())
+			return 0;
+
+		return (arts_stream_t)new Receiver(server,rate,bits,channels,name);
+	}
+
 	void close_stream(arts_stream_t stream)
 	{
 		if(server.isNull())
 			return;
 
-		Sender *sender = (Sender *)stream;
-		if(!sender) return;
+		if(!stream)
+			return;
 
-		sender->close();
+		Sender * _stream = (Sender *)stream;
+		_stream->close();
 	}
 
 	int write(arts_stream_t stream, const void *data, int size)
@@ -462,6 +613,18 @@ public:
 		return sender->write((const mcopbyte *)data,size);
 	}
 
+	int read(arts_stream_t stream, void *data, int size)
+	{
+		if(server.isNull())
+			return ARTS_E_NOSERVER;
+
+		if(!stream)
+			return ARTS_E_NOSTREAM;
+
+		Receiver *receiver = (Receiver *)stream;
+		return receiver->read((mcopbyte *)data,size);
+	}
+
 	int stream_set(arts_stream_t stream, arts_parameter_t param, int value)
 	{
 		if(server.isNull())
@@ -470,8 +633,8 @@ public:
 		if(!stream)
 			return ARTS_E_NOSTREAM;
 
-		Sender *sender = (Sender *)stream;
-		return sender->stream_set(param,value);
+		Receiver *_stream = (Receiver *)stream;
+		return _stream->stream_set(param,value);
 	}
 
 	int stream_get(arts_stream_t stream, arts_parameter_t param)
@@ -482,8 +645,8 @@ public:
 		if(!stream)
 			return ARTS_E_NOSTREAM;
 
-		Sender *sender = (Sender *)stream;
-		return sender->stream_get(param);
+		Receiver *_stream = (Receiver *)stream;
+		return _stream->stream_get(param);
 	}
 
 // allocation and freeing of the class
@@ -550,12 +713,12 @@ extern "C" arts_stream_t arts_backend_pl
 	return ArtsCApi::the()->play_stream(rate,bits,channels,name);
 }
 
-extern "C"arts_stream_t arts_backend_record_stream(int, int, int, const char *)
+extern "C" arts_stream_t arts_backend_record_stream(int rate, int bits, int \
channels, const char *name)  {
 	if(!ArtsCApi::the()) return 0;
 
 	arts_backend_debug("arts_backend_record_stream");
-	return 0;
+	return ArtsCApi::the()->record_stream(rate,bits,channels,name);
 }
 
 extern "C" void arts_backend_close_stream(arts_stream_t stream)
@@ -566,12 +729,12 @@ extern "C" void arts_backend_close_strea
 	ArtsCApi::the()->close_stream(stream);
 }
 
-extern "C"int arts_backend_read(arts_stream_t, void *, int)
+extern "C" int arts_backend_read(arts_stream_t stream, void *buffer, int count)
 {
 	if(!ArtsCApi::the()) return ARTS_E_NOINIT;
 
 	arts_backend_debug("arts_backend_read");
-	return ARTS_E_NOIMPL;
+	return ArtsCApi::the()->read(stream,buffer,count);
 }
 
 extern "C" int arts_backend_write(arts_stream_t stream, const void *buffer,
Index: examples/.cvsignore
===================================================================
RCS file: /home/kde/kdelibs/arts/examples/.cvsignore,v
retrieving revision 1.6
diff -u -3 -p -r1.6 .cvsignore
--- examples/.cvsignore	2000/05/14 17:12:33	1.6
+++ examples/.cvsignore	2001/10/21 19:14:57
@@ -12,6 +12,8 @@ x11commtest
 testwrapper
 streamsound
 artsctest
+artsccat
+artscdump
 flow
 hellomain
 wrapper.h
Index: examples/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/arts/examples/Makefile.am,v
retrieving revision 1.34
diff -u -3 -p -r1.34 Makefile.am
--- examples/Makefile.am	2001/05/19 01:17:01	1.34
+++ examples/Makefile.am	2001/10/21 19:14:57
@@ -10,6 +10,7 @@ FLOWLIBS = $(LDFLAGS) $(top_builddir)/ar
 
 check_PROGRAMS = helloserver helloclient referenceinfo \
   irdemo x11commtest streamsound hellomain flow artsctest \
+  artscdump artsccat \
   dcasttest hellodynamic hellodynamic2 testasubsys testaggregation \
   playtofile tradercheck testthreads testnothreads catfile
 helloserver_SOURCES = hello.cc helloserver.cc hello_impl.cc
@@ -47,6 +48,12 @@ dcasttest_SOURCES = dcasttest.cc
 
 artsctest_LDFLAGS = $(top_builddir)/arts/artsc/libartsc.la
 artsctest_SOURCES = artsctest.c
+
+artsccat_LDFLAGS = $(top_builddir)/arts/artsc/libartsc.la
+artsccat_SOURCES = artsccat.c
+
+artscdump_LDFLAGS = $(top_builddir)/arts/artsc/libartsc.la
+artscdump_SOURCES = artscdump.c
 
 playtofile_SOURCES = playtofile.cc playtofile_impl.cc playtofile_main.cc
 
Index: examples/artsccat.c
===================================================================
RCS file: artsccat.c
diff -N artsccat.c
--- /dev/null	Tue May  5 20:32:27 1998
+++ artsccat.c	Sun Oct 21 19:14:57 2001
@@ -0,0 +1,115 @@
+    /*
+
+    Copyright (C) 2001 Matthias Kretz
+                       kretz@kde.org
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+  
+    This library 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
+    Library General Public License for more details.
+   
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.
+
+    */
+
+/*
+ * This is another artscat written with aRts C API. It reads data from
+ * stdin, and plays it via the aRts soundserver.
+ * 
+ * Compile programs using the aRts C API with
+ * 
+ *    cc -o artscdump artscdump.c `artsc-config --cflags` `artsc-config --libs`
+ *
+ * If you are using a makefile, it could look like this:
+ *
+ *    CFLAGS=`artsc-config --cflags`
+ *    LDFLAGS=`artsc-config --libs`
+ *
+ *    artscdump: artscdump.c
+ */
+#include <artsc.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void exitUsage(const char *progname)
+{
+	fprintf(stderr,"usage: %s [ options ] [ <filename> ]\n",progname);
+	fprintf(stderr,"-r <samplingrate>   set samplingrate to use\n");
+	fprintf(stderr,"-b <bits>           set number of bits (8 or 16)\n");
+	fprintf(stderr,"-c <channels>       set number of channels (1 or 2)\n");
+	fprintf(stderr,"-h                  display this help and exit\n");
+	exit(1);	
+}
+
+int main(int argc, char ** argv)
+{
+	int cfgSamplingRate = 44100;
+	int cfgBits = 16;
+	int cfgChannels = 2;
+	FILE *infile = stdin;
+	int pfd;
+	int packetsize;
+	char *buffer;
+	int size = 1024;
+	arts_stream_t stream;
+	int optch;
+	while((optch = getopt(argc,argv,"r:b:c:h")) > 0)
+	{
+		switch(optch)
+		{
+			case 'r': cfgSamplingRate = atoi(optarg);
+				break;
+			case 'b': cfgBits = atoi(optarg);
+				break;
+			case 'c': cfgChannels = atoi(optarg);
+				break;
+			case 'h':
+			default: 
+					exitUsage(argc?argv[0]:"artsccat");
+				break;
+		}
+	}
+
+	if (optind < argc)
+    {
+		if(argv[optind] != "-")
+		{
+			infile = fopen(argv[optind],"w");
+			if(!infile)
+			{
+				fprintf( stderr, "Can't open file '%s'.\n", argv[optind] );
+				exit(1);
+			}
+		}
+	}
+
+	pfd = fileno( infile );
+
+	arts_init();
+	stream = arts_play_stream( cfgSamplingRate, cfgBits, cfgChannels, "artsccat" );
+	packetsize = arts_stream_get( stream, ARTS_P_PACKET_SIZE );
+	buffer = malloc(packetsize);
+
+	do {
+		size = read( pfd, buffer, packetsize );
+		size = arts_write( stream, buffer, size );
+	} while( size > 0 );
+
+	arts_close_stream( stream );
+	arts_free();
+
+	pclose( infile );
+	free(buffer);
+
+	return 0;
+}
Index: examples/artscdump.c
===================================================================
RCS file: artscdump.c
diff -N artscdump.c
--- /dev/null	Tue May  5 20:32:27 1998
+++ artscdump.c	Sun Oct 21 19:14:57 2001
@@ -0,0 +1,115 @@
+    /*
+
+    Copyright (C) 2001 Matthias Kretz
+                       kretz@kde.org
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+  
+    This library 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
+    Library General Public License for more details.
+   
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.
+
+    */
+
+/*
+ * This is another artsdump written with aRts C API. It reads data from
+ * the aRts soundserver and plays it via stdout.
+ * 
+ * Compile programs using the aRts C API with
+ * 
+ *    cc -o artscdump artscdump.c `artsc-config --cflags` `artsc-config --libs`
+ *
+ * If you are using a makefile, it could look like this:
+ *
+ *    CFLAGS=`artsc-config --cflags`
+ *    LDFLAGS=`artsc-config --libs`
+ *
+ *    artscdump: artscdump.c
+ */
+#include <artsc.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void exitUsage(const char *progname)
+{
+	fprintf(stderr,"usage: %s [ options ] [ <filename> ]\n",progname);
+	fprintf(stderr,"-r <samplingrate>   set samplingrate to use\n");
+	fprintf(stderr,"-b <bits>           set number of bits (8 or 16)\n");
+	fprintf(stderr,"-c <channels>       set number of channels (1 or 2)\n");
+	fprintf(stderr,"-h                  display this help and exit\n");
+	exit(1);	
+}
+
+int main(int argc, char ** argv)
+{
+	int cfgSamplingRate = 44100;
+	int cfgBits = 16;
+	int cfgChannels = 2;
+	FILE *outfile = stdout;
+	int pfd;
+	int packetsize;
+	char *buffer;
+	int size;
+	arts_stream_t stream;
+	int optch;
+	while((optch = getopt(argc,argv,"r:b:c:h")) > 0)
+	{
+		switch(optch)
+		{
+			case 'r': cfgSamplingRate = atoi(optarg);
+				break;
+			case 'b': cfgBits = atoi(optarg);
+				break;
+			case 'c': cfgChannels = atoi(optarg);
+				break;
+			case 'h':
+			default: 
+					exitUsage(argc?argv[0]:"artscdump");
+				break;
+		}
+	}
+
+	if (optind < argc)
+    {
+		if(argv[optind] != "-")
+		{
+			outfile = fopen(argv[optind],"w");
+			if(!outfile)
+			{
+				fprintf( stderr, "Can't open file '%s'.\n", argv[optind] );
+				exit(1);
+			}
+		}
+	}
+
+	pfd = fileno( outfile );
+	
+	arts_init();
+	stream = arts_record_stream( cfgSamplingRate, cfgBits, cfgChannels, "artscdump" );
+	packetsize = arts_stream_get( stream, ARTS_P_PACKET_SIZE );
+	buffer = malloc(packetsize);
+
+	do {
+		size = arts_read( stream, buffer, packetsize );
+		size = write( pfd, buffer, size );
+	} while( size > 0 );
+
+	arts_close_stream( stream );
+	arts_free();
+
+	pclose( outfile );
+	free(buffer);
+
+	return 0;
+}
Index: flow/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/arts/flow/Makefile.am,v
retrieving revision 1.45
diff -u -3 -p -r1.45 Makefile.am
--- flow/Makefile.am	2001/10/12 21:38:08	1.45
+++ flow/Makefile.am	2001/10/21 19:14:57
@@ -26,7 +26,7 @@ libartsflow_la_SOURCES =  synth_play_imp
   bus.cc audiomanager_impl.cc synth_record_impl.cc resample.cc \
   audioio.cc audioiooss.cc audioioalsa.cc audioionull.cc audioiolibaudioio.cc \
   audioiosun.cc audioioaix.cc audioionas.cc cpuinfo.cc \
-  audioioossthreaded.cc
+  audioioossthreaded.cc audiotobytestream_impl.cc
 
 artsincludedir = $(includedir)/arts
 artsinclude_HEADERS = artsflow.h audiosubsys.h cache.h \
Index: flow/artsflow.idl
===================================================================
RCS file: /home/kde/kdelibs/arts/flow/artsflow.idl,v
retrieving revision 1.21
diff -u -3 -p -r1.21 artsflow.idl
--- flow/artsflow.idl	2000/12/07 22:21:15	1.21
+++ flow/artsflow.idl	2001/10/21 19:14:57
@@ -251,6 +251,23 @@ interface ByteStreamToAudio : SynthModul
 };
 
 /**
+ * Audio to Byte stream conversion object
+ *
+ * Converts a synchronous audio stream to an asynchronous byte stream
+ */
+interface AudioToByteStream : SynthModule {
+	attribute long samplingRate;
+	attribute long channels;
+	attribute long bits;
+
+	async out byte stream outdata;
+
+	in audio stream left,right;
+	default left;
+	default right;
+};
+
+/**
  * Base interface for all stereo effects
  */
 interface StereoEffect : SynthModule {
Index: flow/audiotobytestream_impl.cc
===================================================================
RCS file: audiotobytestream_impl.cc
diff -N audiotobytestream_impl.cc
--- /dev/null	Tue May  5 20:32:27 1998
+++ audiotobytestream_impl.cc	Sun Oct 21 19:14:57 2001
@@ -0,0 +1,209 @@
+    /*
+
+    Copyright (C) 2000 Stefan Westerfeld
+                       stefan@space.twc.de
+				  2001 Matthias Kretz
+				       kretz@kde.org
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+  
+    This library 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
+    Library General Public License for more details.
+   
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+    Boston, MA 02111-1307, USA.
+
+    */
+
+#include "artsflow.h"
+#include "stdsynthmodule.h"
+#include "debug.h"
+
+#include <vector>
+#include <iostream>
+#include <math.h>
+
+using namespace std;
+using namespace Arts;
+
+namespace Arts {
+
+class AudioToByteStream_impl : public AudioToByteStream_skel,
+                               public StdSynthModule
+{
+	long m_samplingRate, m_channels, m_bits;
+	long m_sampleSize;
+	double m_step;
+	bool m_interpolate;
+	vector<float> m_left;
+	vector<float> m_right;
+	int m_range;
+	double m_pos;
+protected:
+	void updateSampleSize()
+	{
+		m_sampleSize = m_channels * m_bits / 8;
+	}
+
+public:
+	AudioToByteStream_impl() :
+		m_pos(0)
+	{
+		samplingRate(44100);
+		channels(2);
+		bits(16);
+	}
+
+	long samplingRate() { return m_samplingRate; }
+	void samplingRate(long newRate) {
+		double newStep = samplingRateFloat / (float)newRate;
+		arts_return_if_fail(newStep > 0);
+		m_samplingRate = newRate;
+		m_step = newStep;
+
+		double delta = m_step - floor(m_step);
+		m_interpolate = fabs(delta) > 0.001;
+	}
+
+	long channels() { return m_channels; }
+	void channels(long newChannels) {
+		arts_return_if_fail(newChannels == 1 || newChannels == 2);
+		m_channels = newChannels;
+		updateSampleSize();
+	}
+
+	long bits() { return m_bits; }
+	void bits(long newBits) {
+		arts_return_if_fail(newBits == 8 || newBits == 16);
+		m_bits = newBits;
+		m_range = (newBits == 8 ) ? 128 : 32768;
+		updateSampleSize();
+	}
+
+	void calculateBlock(unsigned long samples)
+	{
+		m_left.resize( 1 + samples );
+		m_right.resize( 1 + samples );
+		for( unsigned long i = 0; i < samples; ++i ) {
+			m_left[1 + i] = (left[i] > 1) ? 1 : (left[i] < -1) ? -1 : left[i];
+			m_right[1 + i] = (right[i] > 1) ? 1 : (right[i] < -1) ? -1 : right[i];
+		}
+
+		int packetstosend = (int)ceil(m_left.size() / m_step);
+		DataPacket<mcopbyte> *packet = outdata.allocPacket( packetstosend * m_sampleSize \
); +
+		int processed = 0;
+		if( m_interpolate ) {
+			double pos = 0;
+			if( m_channels == 2 ) {
+				if( m_bits == 16 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						double error = modf(m_pos, &pos);
+						int intpos = (int)pos;
+						long leftchannel = long((m_left[intpos] * error + m_left[intpos + 1] * (1 - \
error)) * 32768) + 32768; +						long rightchannel = long((m_right[intpos] * error + \
m_right[intpos + 1] * (1 - error)) * 32768) + 32768; \
+						packet->contents[processed * 4    ] = leftchannel; \
+						packet->contents[processed * 4 + 1] = (leftchannel >> 8) - 128; \
+						packet->contents[processed * 4 + 2] = rightchannel; \
+						packet->contents[processed * 4 + 3] = (rightchannel >> 8) - 128; +						m_pos \
+= m_step; +						++processed;
+					}
+				} else if( m_bits == 8 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						double error = modf(m_pos, &pos);
+						int intpos = (int)pos;
+						long leftchannel = long((m_left[intpos] * error + m_left[intpos + 1] * (1 - \
error)) * 128) + 128; +						long rightchannel = long((m_right[intpos] * error + \
m_right[intpos + 1] * (1 - error)) * 128) + 128; +						packet->contents[processed * \
2    ] = leftchannel; +						packet->contents[processed * 2 + 1] = rightchannel;
+						m_pos += m_step;
+						++processed;
+					}
+				}
+			} else {
+				if( m_bits == 16 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						double error = modf(m_pos, &pos);
+						int intpos = (int)pos;
+						long leftchannel = long(((m_left[intpos] + m_right[intpos]) * error + \
(m_left[intpos + 1] + m_right[intpos + 1]) * (1 - error)) * 16384) + 32768; \
+						packet->contents[processed * 2    ] = leftchannel; \
+						packet->contents[processed * 2 + 1] = (leftchannel >> 8) - 128; +						m_pos \
+= m_step; +						++processed;
+					}
+				} else if( m_bits == 8 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						double error = modf(m_pos, &pos);
+						int intpos = (int)pos;
+						long leftchannel = long(((m_left[intpos] + m_right[intpos]) * error + \
(m_left[intpos + 1] + m_right[intpos + 1]) * (1 - error)) * 64) + 128; \
+						packet->contents[processed] = leftchannel; +						m_pos += m_step;
+						++processed;
+					}
+				}
+			}
+		} else {
+			if( m_channels == 2 ) {
+				if( m_bits == 16 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						int intpos = (int)m_pos;
+						long leftchannel = long(m_left[intpos] * 32768) + 32768;
+						long rightchannel = long(m_right[intpos] * 32768) + 32768;
+						packet->contents[processed * 4    ] = leftchannel;
+						packet->contents[processed * 4 + 1] = (leftchannel >> 8) - 128;
+						packet->contents[processed * 4 + 2] = rightchannel;
+						packet->contents[processed * 4 + 3] = (rightchannel >> 8) - 128;
+						m_pos += m_step;
+						++processed;
+					}
+				} else if( m_bits == 8 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						int intpos = (int)m_pos;
+						long leftchannel = long(m_left[intpos] * 128) + 128;
+						long rightchannel = long(m_right[intpos] * 128) + 128;
+						packet->contents[processed * 2    ] = leftchannel;
+						packet->contents[processed * 2 + 1] = rightchannel;
+						m_pos += m_step;
+						++processed;
+					}
+				}
+			} else {
+				if( m_bits == 16 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						int intpos = (int)m_pos;
+						long leftchannel = long((m_left[intpos] + m_right[intpos]) * 16384) + 32768;
+						packet->contents[processed * 2    ] = leftchannel;
+						packet->contents[processed * 2 + 1] = (leftchannel >> 8) - 128;
+						m_pos += m_step;
+						++processed;
+					}
+				} else if( m_bits == 8 ) {
+					while( m_pos < (double)m_left.size() - 1 ) {
+						int intpos = (int)m_pos;
+						long leftchannel = long((m_left[intpos] + m_right[intpos]) * 64) + 128;
+						packet->contents[processed] = leftchannel;
+						m_pos += m_step;
+						++processed;
+					}
+				}
+			}
+		}
+		m_left[0] = m_left.back();
+		m_right[0] = m_right.back();
+		m_pos = m_pos - floor(m_pos);
+		packet->size = processed * m_sampleSize;
+		packet->send();
+	}
+};
+
+REGISTER_IMPLEMENTATION(AudioToByteStream_impl);
+
+};
Index: soundserver/.cvsignore
===================================================================
RCS file: /home/kde/kdelibs/arts/soundserver/.cvsignore,v
retrieving revision 1.8
diff -u -3 -p -r1.8 .cvsignore
--- soundserver/.cvsignore	2001/04/20 19:22:27	1.8
+++ soundserver/.cvsignore	2001/10/21 19:14:58
@@ -2,6 +2,7 @@ Makefile
 Makefile.in
 artsd
 artscat
+artsdump
 artsplay
 artsshell
 artswrapper
Index: soundserver/Makefile.am
===================================================================
RCS file: /home/kde/kdelibs/arts/soundserver/Makefile.am,v
retrieving revision 1.42
diff -u -3 -p -r1.42 Makefile.am
--- soundserver/Makefile.am	2001/10/06 19:22:14	1.42
+++ soundserver/Makefile.am	2001/10/21 19:14:58
@@ -40,7 +40,7 @@ libartswavplayobject_la_LDFLAGS = -no-un
 
 ###### "real" programs
 
-bin_PROGRAMS = artsd artsplay artscat artswrapper artsshell
+bin_PROGRAMS = artsd artsplay artscat artswrapper artsshell artsdump
 
 artsd_LDADD = libsoundserver_idl.la $(FLOWLIBS) \
               $(top_builddir)/arts/mcop_mt/libmcop_mt.la $(USE_THREADS) \
$(LIBPTHREAD) @@ -49,6 +49,9 @@ artsd_SOURCES = soundserverv2_impl.cc so
 artscat_LDADD = libsoundserver_idl.la $(FLOWLIBS)
 artscat_SOURCES = artscat.cc
 
+artsdump_LDADD = libsoundserver_idl.la $(FLOWLIBS)
+artsdump_SOURCES = artsdump.cc
+
 artsplay_LDADD = libsoundserver_idl.la 
 artsplay_SOURCES = artsplay.cc
 
@@ -83,6 +86,7 @@ artsversion.h: artsversion-new.h
 	  || cp artsversion-new.h artsversion.h) 
 
 artscat.cc: soundserver.h artsversion.h
+artsdump.cc: soundserver.h artsversion.h
 artsd.cc: soundserver.h artsversion.h
 artsplay.cc: soundserver.h artsversion.h
 artsshell.cc: soundserver.h artsversion.h
Index: soundserver/artsdump.cc
===================================================================
RCS file: artsdump.cc
diff -N artsdump.cc
--- /dev/null	Tue May  5 20:32:27 1998
+++ artsdump.cc	Sun Oct 21 19:14:58 2001
@@ -0,0 +1,192 @@
+    /*
+
+    Copyright (C) 2000 Stefan Westerfeld
+                       stefan@space.twc.de
+				  2001 Matthias Kretz
+				       kretz@kde.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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.
+
+    Permission is also granted to link this program with the Qt
+    library, treating Qt like a library that normally accompanies the
+    operating system kernel, whether or not that is in fact the case.
+
+    */
+
+#include "soundserver.h"
+#include "stdsynthmodule.h"
+#include "artsversion.h"
+#include "debug.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <iostream>
+
+using namespace std;
+using namespace Arts;
+
+int cfgSamplingRate = 44100;
+int cfgBits = 16;
+int cfgChannels = 2;
+
+class Receiver :	public ByteSoundReceiver_skel,
+				public StdSynthModule,
+				public IONotify
+{
+protected:
+	FILE *pfile;
+	int pfd;
+	int packets;
+	bool waiting;
+	queue< DataPacket<mcopbyte>* > wqueue;
+public:
+	Receiver(FILE *input,float minStreamBufferTime) : pfile(input), waiting(false)
+	{
+		pfd = fileno(pfile);
+
+		int rc = fcntl(pfd, F_SETFL, O_NONBLOCK);
+		assert(rc != -1);
+
+		/*
+		 * calculate stream buffer paramters
+		 */
+		float streamBufferTime;
+		packets = 7;
+		do {
+			packets++;
+			streamBufferTime = (float)(packets * packetCapacity * 1000)
+			                 / (float)(samplingRate() * channels() * 2);
+		} while(streamBufferTime < minStreamBufferTime);
+	}
+
+	~Receiver()
+	{
+		if(waiting) Dispatcher::the()->ioManager()->remove(this,IOType::write);
+	}
+
+	long samplingRate() { return cfgSamplingRate; }
+	long channels()     { return cfgChannels; }
+	long bits()         { return cfgBits; }
+	bool finished()     { return (pfile == 0); }
+
+	enum { packetCapacity = 4096 };
+	void process_indata(DataPacket<mcopbyte> *packet)
+	{
+		if(!waiting)
+		{
+			int size = write( pfd, packet->contents, packet->size );
+			if( size != packet->size ) {
+				arts_debug( "Not written enough" );
+				//Dispatcher::the()->ioManager()->watchFD(pfd,IOType::write,this);
+				//waiting = true;
+			}
+			packet->processed();
+			return;
+		}
+
+		wqueue.push(packet);
+	}
+
+	void notifyIO(int,int)
+	{
+#if 0
+		assert(waiting);
+
+		DataPacket<mcopbyte> *packet = wqueue.front();
+		packet->size = read(pfd, packet->contents, packetCapacity);
+		assert(packet->size >= 0);
+		if(packet->size == 0) {
+			return;
+		}
+		packet->send();
+
+		wqueue.pop();
+
+		if(wqueue.empty())
+		{
+			Dispatcher::the()->ioManager()->remove(this,IOType::write);
+			waiting = false;
+		}
+#endif
+	}
+};
+
+static void exitUsage(const char *progname)
+{
+	fprintf(stderr,"usage: %s [ options ] [ <filename> ]\n",progname);
+	fprintf(stderr,"-r <samplingrate>   set samplingrate to use\n");
+	fprintf(stderr,"-b <bits>           set number of bits (8 or 16)\n");
+	fprintf(stderr,"-c <channels>       set number of channels (1 or 2)\n");
+	fprintf(stderr,"-v                  show version\n");
+	fprintf(stderr,"-h                  display this help and exit\n");
+	exit(1);	
+}
+
+int main(int argc, char **argv)
+{
+	int optch;
+	while((optch = getopt(argc,argv,"r:b:c:hv")) > 0)
+	{
+		switch(optch)
+		{
+			case 'r': cfgSamplingRate = atoi(optarg);
+				break;
+			case 'b': cfgBits = atoi(optarg);
+				break;
+			case 'c': cfgChannels = atoi(optarg);
+				break;
+			case 'v': 
+				printf("artsdump %s\n",ARTS_VERSION);
+				exit(0);
+				break;
+			case 'h':
+			default: 
+					exitUsage(argc?argv[0]:"artsdump");
+				break;
+		}
+	}
+
+	FILE *outfile = stdout;
+
+	if (optind < argc)
+    {
+		string filename = argv[optind];
+		if(filename != "-")
+		{
+			outfile = fopen(filename.c_str(),"w");
+			if(!outfile)
+			{
+				cerr << "Can't open file '" << argv[optind] << "'." << endl;
+				exit(1);
+			}
+		}
+	}                                                                    
+	Dispatcher dispatcher;
+	SimpleSoundServer server(Reference("global:Arts_SimpleSoundServer"));
+
+	if(server.isNull())
+	{
+		cerr << "Can't connect to sound server" << endl;
+		return 1;
+	}
+
+	ByteSoundReceiver receiver = ByteSoundReceiver::_from_base(new \
Receiver(outfile,server.minStreamBufferTime())); +	server.attach(receiver);
+	receiver.start();
+	dispatcher.run();
+	receiver.stop();
+	server.detach(receiver);
+}
Index: soundserver/simplesoundserver_impl.cc
===================================================================
RCS file: /home/kde/kdelibs/arts/soundserver/simplesoundserver_impl.cc,v
retrieving revision 1.36
diff -u -3 -p -r1.36 simplesoundserver_impl.cc
--- soundserver/simplesoundserver_impl.cc	2001/07/04 16:31:06	1.36
+++ soundserver/simplesoundserver_impl.cc	2001/10/21 19:14:58
@@ -2,6 +2,8 @@
 
     Copyright (C) 1999-2001 Stefan Westerfeld
                             stefan@space.twc.de
+					   2001 Matthias Kretz
+					        kretz@kde.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -29,6 +31,8 @@
 #include "audiosubsys.h"
 #include "connect.h"
 #include "debug.h"
+#include "reference.h"
+
 #include <stdio.h>
 #include <iostream>
 
@@ -103,6 +107,8 @@ void PlayStreamJob::detach(const Object&
 void PlayStreamJob::terminate()
 {
 	sender = ByteSoundProducer::null();
+	convert.stop();
+	out.stop();
 }
 
 bool PlayStreamJob::done()
@@ -114,6 +120,57 @@ bool PlayStreamJob::done()
 	return sender.isNull() && !convert.running();
 }
 
+RecordStreamJob::RecordStreamJob(ByteSoundReceiver bsr) : receiver(bsr)
+{
+	int samplingRate = bsr.samplingRate();
+	int channels = bsr.channels();
+	int bits = bsr.bits();
+
+	arts_debug("outgoing stream, parameters: rate=%d, %d bit, %d channels",
+		samplingRate, bits, channels);
+
+	if((samplingRate < 500 || samplingRate > 2000000)
+	|| (channels != 1 && channels != 2) || (bits != 8 && bits != 16))
+	{
+		arts_warning("invalid stream parameters: rate=%d, %d bit, %d channels",
+						samplingRate, bits, channels);
+		terminate();
+		return;
+	}
+
+	convert.samplingRate(samplingRate);
+	convert.channels(channels);
+	convert.bits(bits);
+
+	connect(in,convert);
+	connect(convert,"outdata",receiver,"indata");
+
+	in.start();
+	convert.start();
+}
+
+void RecordStreamJob::detach(const Object& object)
+{
+	if(object._isEqual(receiver))
+		terminate();
+}
+
+void RecordStreamJob::terminate()
+{
+	receiver = ByteSoundReceiver::null();
+	convert.stop();
+	in.stop();
+}
+
+bool RecordStreamJob::done()
+{
+	// when the sender is not alive any longer, assign a null object
+	if(!receiver.isNull() && receiver.error())
+		receiver = ByteSoundReceiver::null();
+
+	return receiver.isNull();
+}
+
 /*
  *    ( This place where other objects for playing wave files and such will
  *      be connected, to get their output mixed with the other clients ).
@@ -205,22 +262,30 @@ float SimpleSoundServer_impl::minStreamB
 	return bufferMultiplier * serverBufferTime();
 }
 
-void SimpleSoundServer_impl::attach(ByteSoundProducer bsp)
+void SimpleSoundServer_impl::attach(SynthModule sm)
 {
-	arts_return_if_fail(!bsp.isNull());
+	arts_return_if_fail(!sm.isNull());
 
-	jobs.push_back(new PlayStreamJob(bsp));
+	if( sm._interfaceName() == "Arts::ByteSoundProducer" ) {
+		ByteSoundProducer bsp = DynamicCast( sm );
+		jobs.push_back(new PlayStreamJob(bsp));
+	} else if( sm._interfaceName() == "Arts::ByteSoundReceiver" ) {
+		ByteSoundReceiver bsr = DynamicCast( sm );
+		jobs.push_back(new RecordStreamJob(bsr));
+	} else {
+		arts_debug( "can't attach unknown stream" );
+	}
 }
 
-void SimpleSoundServer_impl::detach(ByteSoundProducer bsp)
+void SimpleSoundServer_impl::detach(SynthModule sm)
 {
-	arts_return_if_fail(!bsp.isNull());
-	arts_debug("detach incoming stream");
+	arts_return_if_fail(!sm.isNull());
+	arts_debug("detach %s stream", sm._interfaceName().c_str());
 
 	list<SoundServerJob *>::iterator j;
 
 	for(j = jobs.begin();j != jobs.end();j++)
-		(*j)->detach(bsp);
+		(*j)->detach(sm);
 }
 
 StereoEffectStack SimpleSoundServer_impl::outstack()
Index: soundserver/simplesoundserver_impl.h
===================================================================
RCS file: /home/kde/kdelibs/arts/soundserver/simplesoundserver_impl.h,v
retrieving revision 1.21
diff -u -3 -p -r1.21 simplesoundserver_impl.h
--- soundserver/simplesoundserver_impl.h	2001/04/04 17:03:28	1.21
+++ soundserver/simplesoundserver_impl.h	2001/10/21 19:14:58
@@ -2,6 +2,8 @@
 
     Copyright (C) 1999-2000 Stefan Westerfeld
                             stefan@space.twc.de
+					   2001 Matthias Kretz
+					        kretz@kde.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -72,6 +74,21 @@ public:
 	bool done();
 };
 
+class RecordStreamJob : public SoundServerJob
+{
+protected:
+	ByteSoundReceiver receiver;
+	AudioToByteStream convert;
+	Synth_AMAN_RECORD in;
+
+public:
+	RecordStreamJob(ByteSoundReceiver bsr);
+
+	void detach(const Object& object);
+	void terminate();
+	bool done();
+};
+
 class SimpleSoundServer_impl : virtual public SimpleSoundServer_skel,
 										public TimeNotify
 {
@@ -96,8 +113,8 @@ public:
 	// streaming audio
 	float minStreamBufferTime();
 	float serverBufferTime();
-	void attach(ByteSoundProducer bsp);
-	void detach(ByteSoundProducer bsp);
+	void attach(SynthModule sm);
+	void detach(SynthModule sm);
 
 	// simple soundserver interface
 	long play(const std::string& s);
Index: soundserver/soundserver.idl
===================================================================
RCS file: /home/kde/kdelibs/arts/soundserver/soundserver.idl,v
retrieving revision 1.18
diff -u -3 -p -r1.18 soundserver.idl
--- soundserver/soundserver.idl	2001/04/28 18:15:10	1.18
+++ soundserver/soundserver.idl	2001/10/21 19:14:58
@@ -69,6 +69,18 @@ interface ByteSoundProducer : SynthModul
 };
 
 /**
+ * Receiver of byte sound
+ */
+interface ByteSoundReceiver : SynthModule
+{
+	readonly attribute long samplingRate;
+	readonly attribute long channels;
+	readonly attribute long bits;
+
+	async in byte stream indata;
+};
+
+/**
  * This is a very simple sound server interface
  *
  * WARNING: This currently inherits a KMedia2 PlayObjectFactory for test
@@ -119,12 +131,12 @@ interface SimpleSoundServer : PlayObject
 	 * attaches a byte sound producer (read: a client which produces/mixes
 	 * an audio stream itself and just wants playback via the soundserver)
 	 */
-	void attach(ByteSoundProducer producer);
+	void attach(SynthModule sm);
 
 	/**
 	 * detaches a previous attached byte sound producer
 	 */
-	void detach(ByteSoundProducer producer);
+	void detach(SynthModule sm);
 
 	object createObject(string name);
 };


_______________________________________________
kde-multimedia mailing list
kde-multimedia@mail.kde.org
http://mail.kde.org/mailman/listinfo/kde-multimedia

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic