Skip to content

Commit

Permalink
Added empty AlsaInput implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
wedesoft committed Nov 14, 2010
1 parent 6461c28 commit 0f09f24
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 22 deletions.
175 changes: 175 additions & 0 deletions ext/alsainput.cc
@@ -0,0 +1,175 @@
/* HornetsEye - Computer Vision with Ruby
Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
#include "alsainput.hh"

using namespace std;

VALUE AlsaInput::cRubyClass = Qnil;

AlsaInput::AlsaInput( const string &pcmName, unsigned int rate,
unsigned int channels, int periods,
snd_pcm_uframes_t frames ) throw (Error):
m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels )
{
try {
snd_pcm_hw_params_t *hwParams;
snd_pcm_hw_params_alloca( &hwParams );
int err = snd_pcm_open( &m_pcmHandle, m_pcmName.c_str(), SND_PCM_STREAM_CAPTURE,
SND_PCM_NONBLOCK );
ERRORMACRO( err >= 0, Error, , "Error opening PCM device \"" << m_pcmName
<< "\": " << snd_strerror( err ) );
err = snd_pcm_hw_params_any( m_pcmHandle, hwParams );
ERRORMACRO( err >= 0, Error, , "Unable to configure the PCM device \""
<< m_pcmName << "\": " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_access( m_pcmHandle, hwParams,
SND_PCM_ACCESS_RW_INTERLEAVED );
ERRORMACRO( err >= 0, Error, , "Error setting PCM device \""
<< m_pcmName << "\" to interlaced access: " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_format( m_pcmHandle, hwParams,
SND_PCM_FORMAT_S16_LE );
ERRORMACRO( err >= 0, Error, , "Error setting PCM device \"" << m_pcmName
<< "\" to 16-bit signed integer format: " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_rate_near( m_pcmHandle, hwParams, &m_rate, 0 );
ERRORMACRO( err >= 0, Error, , "Error setting sampling rate of PCM device \""
<< m_pcmName << "\" to " << rate << " Hz: " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_channels( m_pcmHandle, hwParams, channels );
ERRORMACRO( err >= 0, Error, , "Error setting number of channels of PCM device \""
<< m_pcmName << "\" to " << channels << ": " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_periods( m_pcmHandle, hwParams, periods, 0 );
ERRORMACRO( err >= 0, Error, , "Error setting number of periods of PCM device \""
<< m_pcmName << "\" to " << periods << ": " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_buffer_size_near( m_pcmHandle, hwParams, &frames );
ERRORMACRO( err >= 0, Error, , "Error setting buffer size of PCM device \""
<< m_pcmName << "\" to " << frames << " frames: "
<< snd_strerror( err ) );
err = snd_pcm_hw_params( m_pcmHandle, hwParams );
ERRORMACRO( err >= 0, Error, , "Error setting parameters of PCM device \""
<< m_pcmName << "\": " << snd_strerror( err ) );
} catch ( Error &e ) {
close();
throw e;
};
}

AlsaInput::~AlsaInput(void)
{
close();
}

void AlsaInput::close(void)
{
if ( m_pcmHandle != NULL ) {
// drop();
snd_pcm_close( m_pcmHandle );
m_pcmHandle = NULL;
};
}

SequencePtr AlsaInput::read(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
<< "\" is not open. Did you call \"close\" before?" );
#if 0
int n = frame->size() / ( 2 * m_channels );
int err;
while ( ( err = snd_pcm_writei( m_pcmHandle, (short int *)frame->data(),
n ) ) < 0 ) {
err = snd_pcm_recover( m_pcmHandle, err, 1 );
ERRORMACRO( err >= 0, Error, , "Error writing audio frames to PCM device \""
<< m_pcmName << "\": " << snd_strerror( err ) );
};
ERRORMACRO( n == err, Error, , "Only managed to write " << err << " of " << n
<< " frames to PCM device \"" << m_pcmName << "\"" );
#endif
SequencePtr sequence( new Sequence( 1024 ) );
return sequence;
}

unsigned int AlsaInput::rate(void)
{
return m_rate;
}

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

VALUE AlsaInput::registerRubyClass( VALUE rbModule )
{
cRubyClass = rb_define_class_under( rbModule, "AlsaInput", rb_cObject );
rb_define_singleton_method( cRubyClass, "new",
RUBY_METHOD_FUNC( wrapNew ), 5 );
rb_define_method( cRubyClass, "close", RUBY_METHOD_FUNC( wrapClose ), 0 );
rb_define_method( cRubyClass, "read", RUBY_METHOD_FUNC( wrapRead ), 0 );
rb_define_method( cRubyClass, "rate", RUBY_METHOD_FUNC( wrapRate ), 0 );
rb_define_method( cRubyClass, "channels", RUBY_METHOD_FUNC( wrapChannels ), 0 );
}

void AlsaInput::deleteRubyObject( void *ptr )
{
delete (AlsaInputPtr *)ptr;
}

VALUE AlsaInput::wrapNew( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
VALUE rbChannels, VALUE rbPeriods, VALUE rbFrames )
{
VALUE retVal = Qnil;
try {
rb_check_type( rbPCMName, T_STRING );
AlsaInputPtr ptr( new AlsaInput( StringValuePtr( rbPCMName ),
NUM2UINT( rbRate ), NUM2UINT( rbChannels ),
NUM2INT( rbPeriods ), NUM2INT( rbFrames ) ) );
retVal = Data_Wrap_Struct( rbClass, 0, deleteRubyObject,
new AlsaInputPtr( ptr ) );
} catch ( exception &e ) {
rb_raise( rb_eRuntimeError, "%s", e.what() );
};
return retVal;
}

VALUE AlsaInput::wrapClose( VALUE rbSelf )
{
AlsaInputPtr *self; Data_Get_Struct( rbSelf, AlsaInputPtr, self );
(*self)->close();
return rbSelf;
}

VALUE AlsaInput::wrapRead( VALUE rbSelf )
{
VALUE rbRetVal = Qnil;
try {
AlsaInputPtr *self; Data_Get_Struct( rbSelf, AlsaInputPtr, self );
SequencePtr sequence( (*self)->read() );
rbRetVal = sequence->rubyObject();
} catch ( exception &e ) {
rb_raise( rb_eRuntimeError, "%s", e.what() );
};
return rbRetVal;
}

VALUE AlsaInput::wrapRate( VALUE rbSelf )
{
AlsaInputPtr *self; Data_Get_Struct( rbSelf, AlsaInputPtr, self );
return UINT2NUM( (*self)->rate() );
}

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

55 changes: 55 additions & 0 deletions ext/alsainput.hh
@@ -0,0 +1,55 @@
/* HornetsEye - Computer Vision with Ruby
Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
#ifndef ALSAINPUT_HH
#define ALSAINPUT_HH

#include <alsa/asoundlib.h>
#include <string>
#include "rubyinc.hh"
#include "error.hh"
#include "sequence.hh"

class AlsaInput
{
public:
AlsaInput( const std::string &pcmName = "default:0",
unsigned int rate = 48000, unsigned int channels = 2,
int periods = 16, snd_pcm_uframes_t frames = 1024 ) throw (Error);
virtual ~AlsaInput(void);
void close(void);
SequencePtr read(void) throw (Error);
unsigned int rate(void);
unsigned int channels(void);
static VALUE cRubyClass;
static VALUE registerRubyClass( VALUE rbModule );
static void deleteRubyObject( void *ptr );
static VALUE wrapNew( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
VALUE rbChannels, VALUE rbPeriods, VALUE rbFrames );
static VALUE wrapClose( VALUE rbSelf );
static VALUE wrapRead( VALUE rbSelf );
static VALUE wrapRate( VALUE rbSelf );
static VALUE wrapChannels( VALUE rbSelf );
protected:
snd_pcm_t *m_pcmHandle;
std::string m_pcmName;
unsigned int m_rate;
unsigned int m_channels;
};

typedef boost::shared_ptr< AlsaInput > AlsaInputPtr;

#endif

21 changes: 4 additions & 17 deletions ext/alsaoutput.cc
Expand Up @@ -21,9 +21,8 @@ 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_channels( channels ),
m_frames( frames )
snd_pcm_uframes_t frames ) throw (Error):
m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels )
{
try {
snd_pcm_hw_params_t *hwParams;
Expand Down Expand Up @@ -52,9 +51,9 @@ AlsaOutput::AlsaOutput( const string &pcmName, unsigned int rate,
err = snd_pcm_hw_params_set_periods( m_pcmHandle, hwParams, periods, 0 );
ERRORMACRO( err >= 0, Error, , "Error setting number of periods of PCM device \""
<< m_pcmName << "\" to " << periods << ": " << snd_strerror( err ) );
err = snd_pcm_hw_params_set_buffer_size_near( m_pcmHandle, hwParams, &m_frames );
err = snd_pcm_hw_params_set_buffer_size_near( m_pcmHandle, hwParams, &frames );
ERRORMACRO( err >= 0, Error, , "Error setting buffer size of PCM device \""
<< m_pcmName << "\" to " << m_frames << " frames: "
<< m_pcmName << "\" to " << frames << " frames: "
<< snd_strerror( err ) );
err = snd_pcm_hw_params( m_pcmHandle, hwParams );
ERRORMACRO( err >= 0, Error, , "Error setting parameters of PCM device \""
Expand Down Expand Up @@ -119,11 +118,6 @@ unsigned int AlsaOutput::channels(void)
return m_channels;
}

unsigned int AlsaOutput::frames(void)
{
return m_frames;
}

int AlsaOutput::avail(void) throw (Error)
{
ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
Expand Down Expand Up @@ -174,7 +168,6 @@ VALUE AlsaOutput::registerRubyClass( VALUE rbModule )
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, "frames", RUBY_METHOD_FUNC( wrapFrames ), 0 );
rb_define_method( cRubyClass, "avail", RUBY_METHOD_FUNC( wrapAvail ), 0 );
rb_define_method( cRubyClass, "delay", RUBY_METHOD_FUNC( wrapDelay ), 0 );
rb_define_method( cRubyClass, "prepare", RUBY_METHOD_FUNC( wrapPrepare ), 0 );
Expand Down Expand Up @@ -255,12 +248,6 @@ VALUE AlsaOutput::wrapChannels( VALUE rbSelf )
return UINT2NUM( (*self)->channels() );
}

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

VALUE AlsaOutput::wrapAvail( VALUE rbSelf )
{
VALUE rbRetVal = Qnil;
Expand Down
5 changes: 1 addition & 4 deletions ext/alsaoutput.hh
Expand Up @@ -27,15 +27,14 @@ class AlsaOutput
public:
AlsaOutput( const std::string &pcmName = "default:0",
unsigned int rate = 48000, unsigned int channels = 2,
int periods = 2, int frames = 1024 ) throw (Error);
int periods = 16, snd_pcm_uframes_t frames = 1024 ) throw (Error);
virtual ~AlsaOutput(void);
void close(void);
void write( SequencePtr sequence ) throw (Error);
void drop(void) throw (Error);
void drain(void) throw (Error);
unsigned int rate(void);
unsigned int channels(void);
unsigned int frames(void);
int avail(void) throw (Error);
int delay(void) throw (Error);
void prepare(void) throw (Error);
Expand All @@ -50,7 +49,6 @@ public:
static VALUE wrapDrain( VALUE rbSelf );
static VALUE wrapRate( VALUE rbSelf );
static VALUE wrapChannels( VALUE rbSelf );
static VALUE wrapFrames( VALUE rbSelf );
static VALUE wrapAvail( VALUE rbSelf );
static VALUE wrapDelay( VALUE rbSelf );
static VALUE wrapPrepare( VALUE rbSelf );
Expand All @@ -59,7 +57,6 @@ protected:
std::string m_pcmName;
unsigned int m_rate;
unsigned int m_channels;
snd_pcm_uframes_t m_frames;
};

typedef boost::shared_ptr< AlsaOutput > AlsaOutputPtr;
Expand Down
2 changes: 2 additions & 0 deletions ext/init.cc
Expand Up @@ -14,6 +14,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "alsaoutput.hh"
#include "alsainput.hh"

#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
Expand All @@ -32,6 +33,7 @@ extern "C" {
rb_require( "multiarray" );
VALUE rbHornetseye = rb_define_module( "Hornetseye" );
AlsaOutput::registerRubyClass( rbHornetseye );
AlsaInput::registerRubyClass( rbHornetseye );
rb_require( "hornetseye_alsa_ext.rb" );
}

Expand Down
42 changes: 42 additions & 0 deletions lib/hornetseye-alsa/alsainput.rb
@@ -0,0 +1,42 @@
# hornetseye-alsa - Play audio data using libalsa
# Copyright (C) 2010 Jan Wedekind
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

# Namespace of Hornetseye computer vision library
module Hornetseye

class AlsaInput

class << self

alias_method :orig_new, :new

def new( pcm_name = 'default:0', rate = 48000, channels = 2, periods = 16,
frames = 1024 )
orig_new pcm_name, rate, channels, periods, frames
end

end

alias_method :orig_read, :read

def read
orig_read
end

end

end

2 changes: 1 addition & 1 deletion lib/hornetseye-alsa/alsaoutput.rb
Expand Up @@ -43,7 +43,7 @@ def write( frame )
raise "Audio frame must have #{channels} channel(s) but had " +
"#{frame.shape.first}"
end
orig_write Sequence( UBYTE, 2 * frame.size ).new( frame.memory )
orig_write Hornetseye::Sequence( UBYTE, 2 * frame.size ).new( frame.memory )
end

end
Expand Down
1 change: 1 addition & 0 deletions lib/hornetseye_alsa_ext.rb
Expand Up @@ -14,4 +14,5 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require 'hornetseye-alsa/alsaoutput'
require 'hornetseye-alsa/alsainput'

0 comments on commit 0f09f24

Please sign in to comment.