|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (C) 2001, 2002 Matthias Kretz
|
|
|
|
kretz@kde.org
|
|
|
|
2003 Arnold Krille
|
|
|
|
arnold@arnoldarts.de
|
|
|
|
|
|
|
|
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., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kaudiorecordstream.h"
|
|
|
|
#include "kaudiorecordstream_p.h"
|
|
|
|
#include "kartsserver.h"
|
|
|
|
|
|
|
|
#include <artsflow.h>
|
|
|
|
#include <soundserver.h>
|
|
|
|
|
|
|
|
#include <tdeglobal.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqptrqueue.h>
|
|
|
|
#include <tqcstring.h> //QByteArray
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
struct KAudioRecordStream::Data
|
|
|
|
{
|
|
|
|
Arts::Synth_AMAN_RECORD in;
|
|
|
|
Arts::AudioToByteStream convert;
|
|
|
|
Arts::StereoEffectStack effectStack;
|
|
|
|
Arts::ByteSoundReceiver receiver;
|
|
|
|
KByteSoundReceiver * receiver_base;
|
|
|
|
KArtsServer * kserver;
|
|
|
|
bool attached;
|
|
|
|
bool blocking;
|
|
|
|
bool polling;
|
|
|
|
unsigned int pos;
|
|
|
|
TQPtrQueue<TQByteArray> inqueue;
|
|
|
|
TQString title;
|
|
|
|
};
|
|
|
|
|
|
|
|
KAudioRecordStream::KAudioRecordStream( KArtsServer * kserver, const TQString & title, TQObject * parent, const char * name )
|
|
|
|
: TQObject( parent, name )
|
|
|
|
, d( new Data )
|
|
|
|
{
|
|
|
|
d->kserver = kserver;
|
|
|
|
d->attached = false;
|
|
|
|
d->blocking = true;
|
|
|
|
d->polling = false;
|
|
|
|
d->pos = 0;
|
|
|
|
d->inqueue.setAutoDelete( true );
|
|
|
|
d->title = title;
|
|
|
|
|
|
|
|
connect( d->kserver, TQT_SIGNAL( restartedServer() ), TQT_SLOT( slotRestartedServer() ) );
|
|
|
|
|
|
|
|
d->in = Arts::DynamicCast( d->kserver->server().createObject( "Arts::Synth_AMAN_RECORD" ) );
|
|
|
|
d->effectStack = Arts::DynamicCast( d->kserver->server().createObject( "Arts::StereoEffectStack" ) );
|
|
|
|
d->convert = Arts::DynamicCast( d->kserver->server().createObject( "Arts::AudioToByteStream" ) );
|
|
|
|
if( d->in.isNull() )
|
|
|
|
kdFatal( 400 ) << "couldn't create a Synth_AMAN_RECORD on the aRts server\n";
|
|
|
|
if( d->effectStack.isNull() )
|
|
|
|
kdFatal( 400 ) << "couldn't create a StereoEffectStack on the aRts server\n";
|
|
|
|
if( d->convert.isNull() )
|
|
|
|
kdFatal( 400 ) << "couldn't create a AudioToByteStream on the aRts server\n";
|
|
|
|
|
|
|
|
d->in.title( ( const char * ) d->title.local8Bit() );
|
|
|
|
Arts::connect( d->in, d->effectStack );
|
|
|
|
d->in.start();
|
|
|
|
d->effectStack.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
KAudioRecordStream::~KAudioRecordStream()
|
|
|
|
{
|
|
|
|
d->receiver = Arts::ByteSoundReceiver::null();
|
|
|
|
// don't delete receiver_base because aRts takes care of that (in the line
|
|
|
|
// above)
|
|
|
|
d->receiver_base = 0;
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KAudioRecordStream::read( char * buffer, int size )
|
|
|
|
{
|
|
|
|
kdDebug( 400 ) << k_funcinfo << endl;
|
|
|
|
unsigned int remaining = size;
|
|
|
|
while( remaining )
|
|
|
|
{
|
|
|
|
if( d->blocking )
|
|
|
|
while( d->inqueue.isEmpty() )
|
|
|
|
Arts::Dispatcher::the()->ioManager()->processOneEvent( true );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( d->inqueue.isEmpty() )
|
|
|
|
Arts::Dispatcher::the()->ioManager()->processOneEvent( false );
|
|
|
|
if( d->inqueue.isEmpty() )
|
|
|
|
return size - remaining;
|
|
|
|
}
|
|
|
|
TQByteArray * data = d->inqueue.head();
|
|
|
|
unsigned int tocopy = kMin( remaining, data->size() - d->pos );
|
|
|
|
memcpy( buffer, data->data() + d->pos, tocopy );
|
|
|
|
d->pos += tocopy;
|
|
|
|
buffer += tocopy;
|
|
|
|
remaining -= tocopy;
|
|
|
|
if( d->pos == data->size() )
|
|
|
|
{
|
|
|
|
d->inqueue.remove();
|
|
|
|
d->pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::setBlockingIO( bool blocking )
|
|
|
|
{
|
|
|
|
d->blocking = blocking;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KAudioRecordStream::blockingIO() const
|
|
|
|
{
|
|
|
|
return d->blocking;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::usePolling( bool polling )
|
|
|
|
{
|
|
|
|
d->polling = polling;
|
|
|
|
if( ! polling )
|
|
|
|
flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KAudioRecordStream::polling() const
|
|
|
|
{
|
|
|
|
return d->polling;
|
|
|
|
}
|
|
|
|
|
|
|
|
Arts::StereoEffectStack KAudioRecordStream::effectStack() const
|
|
|
|
{
|
|
|
|
return d->effectStack;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KAudioRecordStream::running() const
|
|
|
|
{
|
|
|
|
return d->attached;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::stop()
|
|
|
|
{
|
|
|
|
kdDebug( 400 ) << k_funcinfo << endl;
|
|
|
|
if( d->attached )
|
|
|
|
{
|
|
|
|
d->receiver.stop();
|
|
|
|
d->convert.stop();
|
|
|
|
|
|
|
|
Arts::disconnect( d->convert, d->receiver );
|
|
|
|
d->receiver = Arts::ByteSoundReceiver::null();
|
|
|
|
d->receiver_base = 0;
|
|
|
|
|
|
|
|
Arts::disconnect( d->effectStack, d->convert );
|
|
|
|
|
|
|
|
d->attached = false;
|
|
|
|
emit running( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::start( int samplingRate, int bits, int channels )
|
|
|
|
{
|
|
|
|
kdDebug( 400 ) << k_funcinfo << "samplingRate: " << samplingRate << " bits: " << bits << " channels: " << channels << endl;
|
|
|
|
if( ! d->attached )
|
|
|
|
{
|
|
|
|
assert( d->kserver );
|
|
|
|
|
|
|
|
if( ( samplingRate < 500 || samplingRate > 2000000 )
|
|
|
|
|| ( channels != 1 && channels != 2 ) || ( bits != 8 && bits != 16 ) )
|
|
|
|
{
|
|
|
|
kdWarning( 400 ) << "invalid stream parameters: rate=" << samplingRate << ", " << bits << " bit, " << channels << " channels\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->convert.samplingRate( samplingRate );
|
|
|
|
d->convert.channels( channels );
|
|
|
|
d->convert.bits( bits );
|
|
|
|
Arts::connect( d->effectStack, d->convert );
|
|
|
|
|
|
|
|
d->receiver_base = new KByteSoundReceiver( samplingRate, bits, channels, d->title.local8Bit() );
|
|
|
|
d->receiver = Arts::ByteSoundReceiver::_from_base( d->receiver_base );
|
|
|
|
connect( d->receiver_base, TQT_SIGNAL( data( const char *, unsigned int ) ),
|
|
|
|
TQT_SLOT( slotData( const char *, unsigned int ) ) );
|
|
|
|
Arts::connect( d->convert, "outdata", d->receiver, "indata" );
|
|
|
|
|
|
|
|
d->convert.start();
|
|
|
|
d->receiver.start();
|
|
|
|
|
|
|
|
//### needed?
|
|
|
|
Arts::Dispatcher::the()->ioManager()->processOneEvent( false );
|
|
|
|
d->attached = true;
|
|
|
|
emit running( true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::flush()
|
|
|
|
{
|
|
|
|
kdDebug( 400 ) << k_funcinfo << endl;
|
|
|
|
d->inqueue.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KAudioRecordStream::slotRestartedServer() { }
|
|
|
|
|
|
|
|
void KAudioRecordStream::slotData( const char * contents, unsigned int size )
|
|
|
|
{
|
|
|
|
//kdDebug( 400 ) << k_funcinfo << endl;
|
|
|
|
TQByteArray * bytearray = new TQByteArray( size );
|
|
|
|
// copy the contents to the bytearray
|
|
|
|
// this has to be deleted later
|
|
|
|
bytearray->duplicate( contents, size );
|
|
|
|
if( d->polling )
|
|
|
|
{
|
|
|
|
kdDebug( 400 ) << "enqueue the data\n";
|
|
|
|
d->inqueue.enqueue( bytearray );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//kdDebug( 400 ) << "emit the data\n";
|
|
|
|
emit data( *bytearray );
|
|
|
|
//kdDebug( 400 ) << "delete the data\n";
|
|
|
|
delete bytearray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////
|
|
|
|
// ---*--- KByteSoundReceiver ---*--- //
|
|
|
|
////////////////////////////////////////
|
|
|
|
|
|
|
|
KByteSoundReceiver::KByteSoundReceiver( int rate, int bits, int channels, const char * title )
|
|
|
|
: _samplingRate( rate )
|
|
|
|
, _bits( bits )
|
|
|
|
, _channels( channels )
|
|
|
|
, _title( title )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KByteSoundReceiver::~KByteSoundReceiver()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void KByteSoundReceiver::process_indata( Arts::DataPacket<Arts::mcopbyte> * inpacket )
|
|
|
|
{
|
|
|
|
//kdDebug( 400 ) << k_funcinfo << " size of the packet: " << inpacket->size << endl;
|
|
|
|
emit data( (char *)inpacket->contents, inpacket->size );
|
|
|
|
inpacket->processed();
|
|
|
|
}
|
|
|
|
#include "kaudiorecordstream.moc"
|
|
|
|
#include "kaudiorecordstream_p.moc"
|