Commit 81c846ff authored by Emmanuel Milou's avatar Emmanuel Milou

sflphone/src/audio ready for doxygen

parent 76653f79
......@@ -22,8 +22,8 @@
const double AudioDevice::DEFAULT_RATE = 8000.0;
AudioDevice::AudioDevice(int id, const std::string& apiName, const std::string& name) :
_id(id), _apiName(apiName), _name(name)
AudioDevice::AudioDevice(int id, const std::string& name) :
_id(id), _name(name)
{
_rate = DEFAULT_RATE;
}
......
......@@ -20,36 +20,62 @@
#ifndef _AUDIO_DEVICE_H
#define _AUDIO_DEVICE_H
#include <string>
#define AUDIODEVICERATE 8000
/**
* @file audiodevice.c
* @file audiodevice.h
* @brief Container device for attribute storage
* Have almost only get/set method
*/
class AudioDevice {
public:
AudioDevice(int id, const std::string& apiName, const std::string& name);
/**
* Constructor
* @param id
* @param
* @param
*/
AudioDevice(int id, const std::string& name);
/**
* Destructor
*/
~AudioDevice();
/** Default sample rate */
const static double DEFAULT_RATE;
/**
* Read accessor to the ID
* @return int The ID of the audiodevice
*/
int getId() { return _id; }
const std::string& getApiName() {return _apiName; }
/**
* Read accessor to the name
* @return std::string& A string description
*/
const std::string& getName() {return _name; }
/**
* Write accessor to the sample rate
* @param rate The sample rate
*/
void setRate(double rate) { _rate = rate;}
/**
* Read accessor to the sample rate
* @return double The sample rate
*/
double getRate() { return _rate; }
private:
/** Integer id of the device, can not be 0 */
int _id;
/** Host API Name, ex: OSS, ALSA */
std::string _apiName;
/** Name of the device */
std::string _name;
......
......@@ -28,22 +28,57 @@
#include "codecDescriptor.h"
/**
@author Yan Morin <yan.morin@savoirfairelinux.com>
*/
* @file audiofile.h
* @brief A class to manage sound files
*/
class AudioFile : public AudioLoop
{
public:
/**
* Constructor
*/
AudioFile();
/**
* Destructor
*/
~AudioFile();
bool loadFile(const std::string& filename, AudioCodec *codec , unsigned int sampleRate/*=8000*/);
/**
* Load a sound file in memory
* @param filename The absolute path to the file
* @param codec The codec to decode and encode it
* @param sampleRate The sample rate to read it
* @return bool True on success
*/
bool loadFile(const std::string& filename, AudioCodec *codec , unsigned int sampleRate);
/**
* Start the sound file
*/
void start() { _start = true; }
/**
* Stop the sound file
*/
void stop() { _start = false; }
/**
* Tells whether or not the file is playing
* @return bool True if yes
* false otherwise
*/
bool isStarted() { return _start; }
private:
/** The absolute path to the sound file */
std::string _filename;
/** Your preferred codec */
AudioCodec* _codec;
/** Start or not */
bool _start;
};
......
/*
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Copyright (C) 2008 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
*
* 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
......@@ -37,7 +36,6 @@
AudioLayer::AudioLayer(ManagerImpl* manager)
: _defaultVolume(100)
, _errorMessage(-1)
, _manager(manager)
, _PlaybackHandle( NULL )
, _CaptureHandle( NULL )
......@@ -123,13 +121,6 @@ AudioLayer::stopStream(void)
_urgentBuffer.flush();
}
int
AudioLayer::getDeviceCount()
{
// TODO: everything
return 1;
}
void AudioLayer::AlsaCallBack( snd_async_handler_t* pcm_callback )
{
( ( AudioLayer *)snd_async_handler_get_callback_private( pcm_callback )) -> playTones();
......@@ -326,8 +317,6 @@ AudioLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
if( err = snd_pcm_hw_params_set_format( _CaptureHandle, hwParams, SND_PCM_FORMAT_S16_LE) < 0) _debugAlsa(" Cannot set sample format (%s)\n", snd_strerror(err));
if( err = snd_pcm_hw_params_set_rate_near( _CaptureHandle, hwParams, &rate_in, &dir) < 0) _debugAlsa(" Cannot set sample rate (%s)\n", snd_strerror(err));
if( err = snd_pcm_hw_params_set_channels( _CaptureHandle, hwParams, 1) < 0) _debugAlsa(" Cannot set channel count (%s)\n", snd_strerror(err));
//if( err = snd_pcm_hw_params_set_period_size_near( _CaptureHandle, hwParams, &period_size_in , &dir) < 0) _debugAlsa(" Cannot set period size (%s)\n", snd_strerror(err));
//if( err = snd_pcm_hw_params_set_buffer_size_near( _CaptureHandle, hwParams, &buffer_size_in ) < 0) _debugAlsa(" Cannot set buffer size (%s)\n", snd_strerror(err));
if( err = snd_pcm_hw_params_set_period_time_near( _CaptureHandle, hwParams, &period_time , &dir) < 0) _debugAlsa(" Cannot set period time (%s)\n", snd_strerror(err));
if( err = snd_pcm_hw_params_set_buffer_time_near( _CaptureHandle, hwParams, &buffer_time , &dir) < 0) _debugAlsa(" Cannot set buffer time (%s)\n", snd_strerror(err));
if( err = snd_pcm_hw_params_get_period_size( hwParams, &period_size_in , &dir) < 0) _debugAlsa(" Cannot get period size (%s)\n", snd_strerror(err));
......
/*
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Copyright (C) 2004-2008 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
*
* 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
......@@ -23,29 +22,40 @@
#ifndef _AUDIO_LAYER_H
#define _AUDIO_LAYER_H
#include <cc++/thread.h> // for ost::Mutex
#include "../global.h"
#include "audiodevice.h"
#include "ringbuffer.h"
#include <cc++/thread.h> // for ost::Mutex
#include <vector>
#include <alsa/asoundlib.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <sstream>
#define FRAME_PER_BUFFER 160
class RingBuffer;
class ManagerImpl;
/** Associate a sound card index to its string description */
typedef std::pair<int , std::string> HwIDPair;
/**
* @file audiolayer.h
* @brief Main sound class. Manages the data transfers between the application and the hardware.
*/
class AudioLayer {
public:
/**
* Constructor
* @param manager An instance of managerimpl
*/
AudioLayer(ManagerImpl* manager);
/**
* Destructor
*/
~AudioLayer(void);
/**
......@@ -61,7 +71,7 @@ class AudioLayer {
* SFL_PCM_BOTH
* @param plugin The alsa plugin ( dmix , default , front , surround , ...)
*/
bool openDevice(int, int, int, int, int, std::string);
bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream, std::string plugin);
/**
* Start the capture stream and prepare the playback stream.
......@@ -107,8 +117,9 @@ class AudioLayer {
/**
* Send samples to the audio device.
* @params buffer The buffer containing the data to be played ( voice and DTMF )
* @params toCopy The number of samples, in bytes
* @param buffer The buffer containing the data to be played ( voice and DTMF )
* @param toCopy The number of samples, in bytes
* @param isTalking If whether or not the conversation is running
* @return int The number of bytes played
*/
int playSamples(void* buffer, int toCopy, bool isTalking);
......@@ -154,22 +165,50 @@ class AudioLayer {
* @return std::vector<std::string> The vector containing the string description of the card
*/
std::vector<std::string> getSoundCardsInfo( int stream );
/**
* Check if the given index corresponds to an existing sound card and supports the specified streaming mode
* @param card An index
* @param stream The stream mode
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @return bool True if it exists and supports the mode
* false otherwise
*/
bool soundCardIndexExist( int card , int stream );
/**
* An index is associated with its string description
* @param description The string description
* @return int Its index
*/
int soundCardGetIndex( std::string description );
/**
* Write accessor to the error state
* @param error The error code
* Could be: ALSA_PLAYBACK_DEVICE
* ALSA_CAPTURE_DEVICE
*/
void setErrorMessage(const int& error) { _errorMessage = error; }
/**
* Read accessor to the error state
* @return int The error code
*/
int getErrorMessage() { return _errorMessage; }
/**
* Get the index of the audio card for capture
* @return _indexIn The index of the card used for capture
* @return int The index of the card used for capture
* 0 for the first available card on the system, 1 ...
*/
int getIndexIn() { return _indexIn; }
/**
* Get the index of the audio card for playback
* @return _indexOut The index of the card used for playback
* @return int The index of the card used for playback
* 0 for the first available card on the system, 1 ...
*/
int getIndexOut() { return _indexOut; }
......@@ -193,7 +232,6 @@ class AudioLayer {
* @return std::string The name of the audio plugin
*/
std::string getAudioPlugin( void ) { return _audioPlugin; }
std::ofstream _fstream;
/**
* Get the current state. Conversation or not
* @return bool true if playSamples has been called
......@@ -201,14 +239,11 @@ class AudioLayer {
*/
bool getCurrentState( void ) { return _talk; }
int getDeviceCount();
/**
* Toggle echo testing on/off
*/
void toggleEchoTesting();
private:
/**
......@@ -231,8 +266,9 @@ class AudioLayer {
/**
* Callback used for asynchronous playback.
* Called when a certain amount of data is written ot the device
* @param pcm_callback The callback pointer
*/
static void AlsaCallBack( snd_async_handler_t* );
static void AlsaCallBack( snd_async_handler_t* pcm_callback);
/**
* Callback used for asynchronous playback.
......@@ -244,8 +280,8 @@ class AudioLayer {
* Open the specified device.
* ALSA Library API
* @param pcm_p The string name for the playback device
* pcm_c The string name for the capture device
* flag To indicate which kind of stream you want to open
* @param pcm_c The string name for the capture device
* @param flag To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
......@@ -258,7 +294,7 @@ class AudioLayer {
* Copy a data buffer in the internal ring buffer
* ALSA Library API
* @param buffer The data to be copied
* length The size of the buffer
* @param length The size of the buffer
* @return int The number of frames actually copied
*/
int write( void* buffer, int length);
......@@ -267,7 +303,7 @@ class AudioLayer {
* Read data from the internal ring buffer
* ALSA Library API
* @param buffer The buffer to stock the read data
* toCopy The number of bytes to get
* @param toCopy The number of bytes to get
* @return int The number of frames actually read
*/
int read( void* buffer, int toCopy);
......@@ -277,16 +313,31 @@ class AudioLayer {
* ALSA Library API
*/
void handle_xrun_capture( void );
void handle_xrun_playback( void );
ManagerImpl* _manager; // augment coupling, reduce indirect access
/**
* Recover from XRUN state for playback
* ALSA Library API
*/
void handle_xrun_playback( void );
/** Augment coupling, reduce indirect access */
ManagerImpl* _manager;
/**
* Handles to manipulate capture and playback streams
* Handles to manipulate playback stream
* ALSA Library API
*/
snd_pcm_t* _PlaybackHandle;
/**
* Handles to manipulate capture stream
* ALSA Library API
*/
snd_pcm_t* _CaptureHandle;
/**
* Alsa parameter - Size of a period in the hardware ring buffer
*/
snd_pcm_uframes_t _periodSize;
/**
......@@ -299,6 +350,12 @@ class AudioLayer {
*/
RingBuffer _urgentBuffer;
/**
* Volume is controlled by the application. Data buffer are modified here to adjust to the right volume selected by the user on the main interface
* @param buffer The buffer to adjust
* @param len The number of bytes
* @param stream The stream mode ( PLAYBACK - CAPTURE )
*/
void * adjustVolume( void * , int , int);
/**
......@@ -316,9 +373,13 @@ class AudioLayer {
bool deviceClosed;
/**
* Number of audio cards on which stream has been opened
* Number of audio cards on which capture stream has been opened
*/
int _indexIn;
/**
* Number of audio cards on which playback stream has been opened
*/
int _indexOut;
/**
......@@ -341,12 +402,12 @@ class AudioLayer {
/**
* Input channel (mic) should be 1 mono
*/
unsigned int _inChannel; // mic
unsigned int _inChannel;
/**
* Output channel (stereo) should be 1 mono
*/
unsigned int _outChannel; // speaker
unsigned int _outChannel;
/**
* Default volume for incoming RTP and Urgent sounds.
......@@ -358,12 +419,13 @@ class AudioLayer {
*/
bool _echoTesting;
/** Vector to manage all soundcard index - description association of the system */
std::vector<HwIDPair> IDSoundCards;
/** Contains the current error code */
int _errorMessage;
ost::Mutex _mutex;
ost::Mutex _mutex;
};
#endif // _AUDIO_LAYER_H_
......@@ -26,33 +26,58 @@
#include "../global.h" // for int16 declaration
/**
* @author Yan Morin <yan.morin@savoirfairelinux.com>
* @file audioloop.h
* @brief Loop on a sound file
*/
class AudioLoop {
public:
/**
* Constructor
*/
AudioLoop();
/**
* Virtual destructor
*/
virtual ~AudioLoop();
/**
* get the next fragment of the tone
* Get the next fragment of the tone
* the function change the intern position, and will loop
* @param output The data buffer
* @param nb of int16 to send
* @param volume The volume
* @return the number of int16 sent (nb*2)
*/
int getNext(SFLDataFormat* output, int nb, short volume=100);
/**
* Reset the pointer position
*/
void reset() { _pos = 0; }
unsigned int getMonoSize() { return _size; }
/**
* Accessor to the size of the buffer
* @return unsigned int The size
*/
unsigned int getSize() { return _size; }
protected:
/** The data buffer */
SFLDataFormat* _buffer;
int _size; // number of int16 inside the buffer, not the delay
int _pos; // current position, set to 0, when initialize
int _sampleRate; // last samplerate
};
/** Number of int16 inside the buffer, not the delay */
int _size;
/** current position, set to 0, when initialize */
int _pos;
/** Sample rate */
int _sampleRate;
};
#endif // __AUDIOLOOP_H__
/*
*
* Copyright (C) 2004-2007 Savoir-Faire Linux inc.
* Copyright (C) 2004-2008 Savoir-Faire Linux inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
......@@ -97,7 +97,6 @@ AudioRtp::closeRtpSession () {
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym)
: _fstream("/tmp/audio.gsm", std::ofstream::binary|std::ios::out|std::ios::app)
{
setCancel(cancelDeferred);
time = new ost::Time();
......
/*
* Copyright (C) 2004-2007 Savoir-Faire Linux inc.
* Copyright (C) 2004-2008 Savoir-Faire Linux inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
......@@ -24,19 +24,20 @@
#include <cstdio>
#include <cstdlib>
#include <fstream> // fstream + iostream for _fstream debugging...
#include <iostream>
#include <ccrtp/rtp.h>
#include <cc++/numbers.h>
#include <samplerate.h>
#include "../global.h"
#define UP_SAMPLING 0
#define DOWN_SAMPLING 1
/**
* @file audiortp.h
* @brief Manage the real-time data transport in a SIP call
*/
class SIPCall;
......@@ -44,101 +45,170 @@ class SIPCall;
// Two pair of sockets
///////////////////////////////////////////////////////////////////////////////
class AudioRtpRTX : public ost::Thread, public ost::TimerPort {
public:
AudioRtpRTX (SIPCall *, bool);
~AudioRtpRTX();
ost::Time *time; // For incoming call notification
virtual void run ();
private:
SIPCall* _ca;
ost::RTPSession *_sessionSend;
ost::RTPSession *_sessionRecv;
ost::SymmetricRTPSession *_session;
ost::Semaphore _start;
bool _sym;
/** When we receive data, we decode it inside this buffer */
int16* _receiveDataDecoded;
/** Buffers used for send data from the mic */
unsigned char* _sendDataEncoded;
int16* _intBufferDown;
/** After that we send the data inside this buffer if there is a format conversion or rate conversion */
/** Also use for getting mic-ringbuffer data */
SFLDataFormat* _dataAudioLayer;
/** Buffers used for sample rate conversion */
float32* _floatBufferDown;
float32* _floatBufferUp;
/** Debugging output file */
std::ofstream _fstream;
FILE* fd;
/** libsamplerate converter for incoming voice */
SRC_STATE* _src_state_spkr;
/** libsamplerate converter for outgoing voice */
SRC_STATE* _src_state_mic;
/** libsamplerate error */
int _src_err;
// Variables to process audio stream
int _layerSampleRate; // sample rate for playing sound (typically 44100HZ)
int _codecSampleRate; // sample rate of the codec we use to encode and decode (most of time 8000HZ)
int _layerFrameSize; // length of the sound frame we capture in ms(typically 20ms)
void initAudioRtpSession(void);
/**
* Get the data from the mic, encode it and send it through the RTP session
*/
void sendSessionFromMic(int);
/**
* Get the data from the RTP packets, decode it and send it to the sound card
*/
void receiveSessionForSpkr(int&);
/**
* Init the buffers used for processing sound data
*/
void initBuffers(void);
/**
* Call the appropriate function, up or downsampling
*/
int reSampleData(int, int ,int);
/**
* Upsample the data from the clock rate of the codec to the sample rate of the layer
* @param int The clock rate of the codec
* @param int The number of samples we have in the buffer
* @return int The number of samples after the operation
*/
int upSampleData(int, int);
/**
* Downsample the data from the sample rate of the layer to the clock rate of the codec
* @param int The clock rate of the codec
* @param int The number of samples we have in the buffer
* @return int The number of samples after the operation
*/
int downSampleData(int, int);
AudioCodec* _audiocodec;
public:
/**
* Constructor
* @param sipcall The pointer on the SIP call
* @param sym Tells whether or not the voip links are symmetric
*/
AudioRtpRTX (SIPCall* sipcall, bool sym);
/**
* Destructor
*/
~AudioRtpRTX();
/** For incoming call notification */
ost::Time *time;
/** Thread associated method */
virtual void run ();
private:
/** A SIP call */
SIPCall* _ca;
/** RTP session to send data */
ost::RTPSession *_sessionSend;
/** RTP session to receive data */
ost::RTPSession *_sessionRecv;
/** RTP symmetric session ( receive and send data in the same session ) */
ost::SymmetricRTPSession *_session;
/** Semaphore */
ost::Semaphore _start;
/** Is the session symmetric or not */
bool _sym;
/** When we receive data, we decode it inside this buffer */
int16* _receiveDataDecoded;
/** Buffers used for send data from the mic */
unsigned char* _sendDataEncoded;
/** Downsampled int16 buffer */
int16* _intBufferDown;
/** After that we send the data inside this buffer if there is a format conversion or rate conversion */
/** Also use for getting mic-ringbuffer data */
SFLDataFormat* _dataAudioLayer;
/** Downsampled float buffer */
float32* _floatBufferDown;
/** Upsampled float buffer */
float32* _floatBufferUp;
/** libsamplerate converter for incoming voice */
SRC_STATE* _src_state_spkr;
/** libsamplerate converter for outgoing voice */
SRC_STATE* _src_state_mic;
/** libsamplerate error */
int _src_err;
/** Variables to process audio stream: sample rate for playing sound (typically 44100HZ) */
int _layerSampleRate;
/** Sample rate of the codec we use to encode and decode (most of time 8000HZ) */
int _codecSampleRate;
/** Length of the sound frame we capture in ms(typically 20ms) */
int _layerFrameSize;
/**
* Init the RTP session. Create either symmetric or double sessions to manage data transport
* Set the payloads according to the manager preferences
*/
void initAudioRtpSession(void);
/**
* Get the data from the mic, encode it and send it through the RTP session
* @param timestamp To manage time and synchronizing
*/
void sendSessionFromMic(int timestamp);
/**
* Get the data from the RTP packets, decode it and send it to the sound card
* @param countTime To manage time and synchronizing
*/
void receiveSessionForSpkr(int& countTime);
/**
* Init the buffers used for processing sound data
*/
void initBuffers(void);
/**
* Call the appropriate function, up or downsampling
* @param sampleRate_codec The sample rate of the codec selected to encode/decode the data
* @param nbSamples Number of samples to process
* @param status Type of resampling
* UPSAMPLING
* DOWNSAMPLING
* @return int The number of samples after process
*/
int reSampleData(int sampleRate_codec, int nbSamples, int status);