Skip to content

Commit

Permalink
Added audio without multithreading
Browse files Browse the repository at this point in the history
  • Loading branch information
wedesoft committed Oct 19, 2010
1 parent 1d09d53 commit 5937aca
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 4 deletions.
68 changes: 64 additions & 4 deletions ext/alsaoutput.cc
Expand Up @@ -22,7 +22,7 @@ VALUE AlsaOutput::cRubyClass = Qnil;
AlsaOutput::AlsaOutput( const string &pcmName, unsigned int rate,
unsigned int channels, int periods,
int frames ) throw (Error):
m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate )
m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels )
{
try {
snd_pcm_hw_params_t *hwParams;
Expand Down Expand Up @@ -81,18 +81,24 @@ void AlsaOutput::close(void)

void AlsaOutput::write( SequencePtr frame ) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
int err = snd_pcm_writei( m_pcmHandle, (short int *)frame->data(),
frame->size() / ( 2 * m_channels ) );
ERRORMACRO( err >= 0, Error, , "Error writing audio frames to PCM device \""
<< m_pcmName << "\": " << snd_strerror( err ) );
}

void AlsaOutput::drop(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "ALSA device \"" << m_pcmName
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
snd_pcm_drop( m_pcmHandle );
}

void AlsaOutput::drain(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "ALSA device \"" << m_pcmName
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
snd_pcm_drain( m_pcmHandle );
}
Expand All @@ -102,9 +108,14 @@ unsigned int AlsaOutput::rate(void)
return m_rate;
}

unsigned int AlsaOutput::channels(void)
{
return m_channels;
}

int AlsaOutput::availUpdate(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "ALSA device \"" << m_pcmName
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
snd_pcm_sframes_t frames = snd_pcm_avail_update( m_pcmHandle );
ERRORMACRO( frames >= 0, Error, , "Error querying number of available frames for "
Expand All @@ -113,6 +124,24 @@ int AlsaOutput::availUpdate(void) throw (Error)
return frames;
}

void AlsaOutput::wait( int milliSeconds ) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
int err = snd_pcm_wait( m_pcmHandle, milliSeconds );
ERRORMACRO( err >= 0, Error, , "Error waiting for PCM device \"" << m_pcmName
<< "\": " << snd_strerror( err ) );
}

void AlsaOutput::prepare(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
int err = snd_pcm_prepare( m_pcmHandle );
ERRORMACRO( err >= 0, Error, , "Error preparing PCM device \"" << m_pcmName
<< "\": " << snd_strerror( err ) );
}

VALUE AlsaOutput::registerRubyClass( VALUE rbModule )
{
cRubyClass = rb_define_class_under( rbModule, "AlsaOutput", rb_cObject );
Expand All @@ -123,8 +152,11 @@ VALUE AlsaOutput::registerRubyClass( VALUE rbModule )
rb_define_method( cRubyClass, "drop", RUBY_METHOD_FUNC( wrapDrop ), 0 );
rb_define_method( cRubyClass, "drain", RUBY_METHOD_FUNC( wrapDrain ), 0 );
rb_define_method( cRubyClass, "rate", RUBY_METHOD_FUNC( wrapRate ), 0 );
rb_define_method( cRubyClass, "channels", RUBY_METHOD_FUNC( wrapChannels ), 0 );
rb_define_method( cRubyClass, "avail_update",
RUBY_METHOD_FUNC( wrapAvailUpdate ), 0 );
rb_define_method( cRubyClass, "wait", RUBY_METHOD_FUNC( wrapWait ), 1 );
rb_define_method( cRubyClass, "prepare", RUBY_METHOD_FUNC( wrapPrepare ), 0 );
}

void AlsaOutput::deleteRubyObject( void *ptr )
Expand Down Expand Up @@ -196,6 +228,12 @@ VALUE AlsaOutput::wrapRate( VALUE rbSelf )
return UINT2NUM( (*self)->rate() );
}

VALUE AlsaOutput::wrapChannels( VALUE rbSelf )
{
AlsaOutputPtr *self; Data_Get_Struct( rbSelf, AlsaOutputPtr, self );
return UINT2NUM( (*self)->channels() );
}

VALUE AlsaOutput::wrapAvailUpdate( VALUE rbSelf )
{
VALUE rbRetVal = Qnil;
Expand All @@ -208,3 +246,25 @@ VALUE AlsaOutput::wrapAvailUpdate( VALUE rbSelf )
return rbRetVal;
}

VALUE AlsaOutput::wrapWait( VALUE rbSelf, VALUE rbMilliSeconds )
{
try {
AlsaOutputPtr *self; Data_Get_Struct( rbSelf, AlsaOutputPtr, self );
(*self)->wait( NUM2INT( rbMilliSeconds ) );
} catch ( exception &e ) {
rb_raise( rb_eRuntimeError, "%s", e.what() );
};
return rbSelf;
}

VALUE AlsaOutput::wrapPrepare( VALUE rbSelf )
{
try {
AlsaOutputPtr *self; Data_Get_Struct( rbSelf, AlsaOutputPtr, self );
(*self)->prepare();
} catch ( exception &e ) {
rb_raise( rb_eRuntimeError, "%s", e.what() );
};
return rbSelf;
}

7 changes: 7 additions & 0 deletions ext/alsaoutput.hh
Expand Up @@ -34,7 +34,10 @@ public:
void drop(void) throw (Error);
void drain(void) throw (Error);
unsigned int rate(void);
unsigned int channels(void);
int availUpdate(void) throw (Error);
void wait( int milliSeconds ) throw (Error);
void prepare(void) throw (Error);
static VALUE cRubyClass;
static VALUE registerRubyClass( VALUE rbModule );
static void deleteRubyObject( void *ptr );
Expand All @@ -45,11 +48,15 @@ public:
static VALUE wrapDrop( VALUE rbSelf );
static VALUE wrapDrain( VALUE rbSelf );
static VALUE wrapRate( VALUE rbSelf );
static VALUE wrapChannels( VALUE rbSelf );
static VALUE wrapAvailUpdate( VALUE rbSelf );
static VALUE wrapWait( VALUE rbSelf, VALUE rbMilliSeconds );
static VALUE wrapPrepare( VALUE rbSelf );
protected:
snd_pcm_t *m_pcmHandle;
std::string m_pcmName;
unsigned int m_rate;
unsigned int m_channels;
};

typedef boost::shared_ptr< AlsaOutput > AlsaOutputPtr;
Expand Down
22 changes: 22 additions & 0 deletions lib/hornetseye-alsa/alsaoutput.rb
Expand Up @@ -30,6 +30,28 @@ def new( pcm_name = 'default:0', rate = 48000, channels = 2, periods = 2,

end

alias_method :orig_write, :write

def write( frame )
if frame.typecode != SINT
raise "Audio data must be of type SINT (but was #{frame.typecode})"
end
if frame.dimension != 2
raise "Audio frame must have two dimensions (but had #{frame.dimension})"
end
if frame.shape.first != channels
raise "Audio frame must have #{channels} channel(s) but had " +
"#{frame.shape.first}"
end
orig_write Sequence( UBYTE, 2 * frame.size ).new( frame.memory )
end

alias_method :orig_wait, :wait

def wait( time = 1 )
orig_wait ( time * 1000 ).to_i
end

end

end
Expand Down

0 comments on commit 5937aca

Please sign in to comment.