mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
Each pulse audio streams is an object now
This commit is contained in:
@ -23,15 +23,15 @@ endif
|
||||
SUBDIRS = codecs
|
||||
|
||||
libaudio_la_SOURCES = audiofile.cpp tonelist.cpp \
|
||||
audiortp.cpp dtmf.cpp tone.cpp alsalayer.cpp pulselayer.cpp audiodevice.cpp dtmfgenerator.cpp \
|
||||
tonegenerator.cpp codecDescriptor.cpp \
|
||||
audiortp.cpp audiostream.cpp dtmf.cpp tone.cpp alsalayer.cpp pulselayer.cpp audiodevice.cpp dtmfgenerator.cpp \
|
||||
tonegenerator.cpp codecDescriptor.cpp samplecache.cpp\
|
||||
audioloop.cpp ringbuffer.cpp $(SPEEX_SOURCES_CPP)
|
||||
|
||||
AM_CXXFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/libs $(libccext2_CFLAGS) $(libdbuscpp_CFLAGS) $(libccrtp1_CFLAGS) $(USER_INCLUDES) \
|
||||
-DCODECS_DIR=\""$(sflcodecdir)"\" $(SPEEX_FLAG) $(GSM_FLAG) $(ILBC_FLAG)
|
||||
|
||||
noinst_HEADERS = audioloop.h common.h ringbuffer.h audiofile.h \
|
||||
noinst_HEADERS = audioloop.h audiostream.h common.h ringbuffer.h audiofile.h \
|
||||
tonelist.h audiortp.h audiolayer.h alsalayer.h pulselayer.h audiodevice.h \
|
||||
dtmfgenerator.h tonegenerator.h \
|
||||
dtmfgenerator.h tonegenerator.h samplecache.h \
|
||||
codecDescriptor.h dtmf.h tone.h
|
||||
|
||||
|
95
src/audio/audiostream.cpp
Normal file
95
src/audio/audiostream.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <audiostream.h>
|
||||
|
||||
static pa_channel_map channel_map ;
|
||||
|
||||
AudioStream::AudioStream( pa_context* context, int type, std::string desc )
|
||||
{
|
||||
_streamType = type;
|
||||
_streamDescription = desc;
|
||||
sample_spec.format = PA_SAMPLE_S16LE;
|
||||
sample_spec.rate = 44100;
|
||||
sample_spec.channels = 1;
|
||||
channel_map.channels = 1;
|
||||
flag = PA_STREAM_AUTO_TIMING_UPDATE;
|
||||
|
||||
_audiostream = createStream( context );
|
||||
}
|
||||
|
||||
AudioStream::~AudioStream()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AudioStream::stream_state_callback( pa_stream* s, void* user_data )
|
||||
{
|
||||
_debug("The state of the stream changed\n");
|
||||
assert(s);
|
||||
switch(pa_stream_get_state(s)){
|
||||
case PA_STREAM_CREATING:
|
||||
case PA_STREAM_TERMINATED:
|
||||
_debug("Stream is creating...\n");
|
||||
break;
|
||||
case PA_STREAM_READY:
|
||||
_debug("Stream successfully created\n");
|
||||
break;
|
||||
case PA_STREAM_FAILED:
|
||||
default:
|
||||
_debug("Stream error: %s\n" , pa_strerror(pa_context_errno(pa_stream_get_context(s))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pa_stream*
|
||||
AudioStream::createStream( pa_context* c )
|
||||
{
|
||||
_debug("Creating %s stream...\n" , _streamDescription.c_str());
|
||||
pa_stream* s;
|
||||
|
||||
assert(pa_sample_spec_valid(&sample_spec));
|
||||
assert(pa_channel_map_valid(&channel_map));
|
||||
|
||||
if( !( s = pa_stream_new( c, _streamDescription.c_str() , &sample_spec, &channel_map ) ) )
|
||||
_debug("%s: pa_stream_new() failed : %s\n" , _streamDescription.c_str(), pa_strerror( pa_context_errno( c)));
|
||||
|
||||
assert( s );
|
||||
|
||||
if( _streamType == PLAYBACK_STREAM ){
|
||||
pa_stream_connect_playback( s , NULL , NULL , flag , NULL, NULL );
|
||||
//pa_stream_set_write_callback( s , audioCallback, this);
|
||||
}
|
||||
else if( _streamType == CAPTURE_STREAM ){
|
||||
pa_stream_connect_record( s , NULL , NULL , flag );
|
||||
//pa_stream_set_read_callback( s , audioCallback, this);
|
||||
}
|
||||
else if( _streamType == UPLOAD_STREAM ){
|
||||
//pa_stream_connect_upload( s , 1024 );
|
||||
}
|
||||
else{
|
||||
_debug( "Stream type unknown \n");
|
||||
}
|
||||
|
||||
pa_stream_set_state_callback( s , stream_state_callback, NULL);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
65
src/audio/audiostream.h
Normal file
65
src/audio/audiostream.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _AUDIO_STREAM_H
|
||||
#define _AUDIO_STREAM_H
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <string>
|
||||
|
||||
#include "../global.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "audioloop.h"
|
||||
|
||||
enum STREAM_TYPE {
|
||||
PLAYBACK_STREAM,
|
||||
CAPTURE_STREAM,
|
||||
UPLOAD_STREAM
|
||||
};
|
||||
|
||||
|
||||
class AudioStream {
|
||||
public:
|
||||
AudioStream(pa_context* context , int type, std::string desc);
|
||||
~AudioStream();
|
||||
|
||||
int putMain( void* buffer , int toCopy );
|
||||
int putUrgent( void* buffer , int toCopy );
|
||||
|
||||
pa_stream* pulseStream(){ return _audiostream; }
|
||||
|
||||
private:
|
||||
pa_stream* createStream( pa_context* c );
|
||||
|
||||
static void stream_state_callback( pa_stream* s, void* user_data );
|
||||
static void audioCallback ( pa_stream* s, size_t bytes, void* userdata );
|
||||
void write( void );
|
||||
|
||||
int _streamType;
|
||||
std::string _streamDescription;
|
||||
|
||||
|
||||
pa_stream* _audiostream;
|
||||
pa_stream_flags_t flag;
|
||||
pa_sample_spec sample_spec ;
|
||||
//pa_channel_map channel_map;
|
||||
|
||||
};
|
||||
|
||||
#endif // _AUDIO_STREAM_H
|
@ -77,3 +77,4 @@ DTMF::generateDTMF (SFLDataFormat* buffer, size_t n)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,23 +19,13 @@
|
||||
|
||||
#include "pulselayer.h"
|
||||
|
||||
static pa_context *context = NULL;
|
||||
static pa_stream* playback = NULL;
|
||||
static pa_stream* record = NULL;
|
||||
static pa_mainloop_api *mainloop_api = NULL;
|
||||
static pa_threaded_mainloop *m = NULL;
|
||||
|
||||
static pa_sample_spec sample_spec ;
|
||||
int framesPerBuffer = 1024;
|
||||
|
||||
static pa_channel_map channel_map;
|
||||
|
||||
static std::string pcm_p, pcm_r;
|
||||
|
||||
int framesPerBuffer = 882;
|
||||
|
||||
PulseLayer::PulseLayer(ManagerImpl* manager)
|
||||
PulseLayer::PulseLayer(ManagerImpl* manager)
|
||||
: AudioLayer( manager , PULSEAUDIO )
|
||||
, _mainSndRingBuffer( SIZEBUF )
|
||||
, _urgentRingBuffer( SIZEBUF)
|
||||
,_mainSndRingBuffer( SIZEBUF )
|
||||
{
|
||||
_debug("Pulse audio constructor: Create context\n");
|
||||
}
|
||||
@ -43,11 +33,10 @@ int framesPerBuffer = 882;
|
||||
// Destructor
|
||||
PulseLayer::~PulseLayer (void)
|
||||
{
|
||||
assert(mainloop_api);
|
||||
//mainloop_api->quit( mainloop_api, 0 );
|
||||
pa_stream_flush( playback , NULL, NULL);
|
||||
pa_stream_disconnect( playback );
|
||||
pa_context_disconnect(context);
|
||||
delete playback;
|
||||
delete record;
|
||||
////delete cache;
|
||||
pa_context_disconnect(context);
|
||||
}
|
||||
|
||||
void
|
||||
@ -75,33 +64,12 @@ PulseLayer::connectPulseServer( void )
|
||||
_debug("Context creation done\n");
|
||||
}
|
||||
|
||||
void
|
||||
PulseLayer::stream_state_callback( pa_stream* s, void* user_data )
|
||||
{
|
||||
_debug("The state of the stream changed\n");
|
||||
assert(s);
|
||||
switch(pa_stream_get_state(s)){
|
||||
case PA_STREAM_CREATING:
|
||||
case PA_STREAM_TERMINATED:
|
||||
_debug("Stream is creating...\n");
|
||||
break;
|
||||
case PA_STREAM_READY:
|
||||
_debug("Stream successfully created\n");
|
||||
break;
|
||||
case PA_STREAM_FAILED:
|
||||
default:
|
||||
_debug("Stream error: %s\n" , pa_strerror(pa_context_errno(pa_stream_get_context(s))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PulseLayer::context_state_callback( pa_context* c, void* user_data )
|
||||
{
|
||||
_debug("The state of the context changed\n");
|
||||
PulseLayer* pulse = (PulseLayer*)user_data;
|
||||
//pa_stream_flags_t flag = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE ;
|
||||
assert(c && m);
|
||||
assert(c && pulse->m);
|
||||
switch(pa_context_get_state(c)){
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
@ -110,7 +78,6 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data )
|
||||
break;
|
||||
case PA_CONTEXT_READY:
|
||||
pa_cvolume cv;
|
||||
assert(c && !playback && !record);
|
||||
pulse->createStreams( c );
|
||||
_debug("Connection to PulseAudio server established\n");
|
||||
break;
|
||||
@ -119,7 +86,7 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data )
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
default:
|
||||
_debug(" Error : %s" , pa_strerror(pa_context_errno(context)));
|
||||
_debug(" Error : %s" , pa_strerror(pa_context_errno(c)));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -127,47 +94,13 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data )
|
||||
void
|
||||
PulseLayer::createStreams( pa_context* c )
|
||||
{
|
||||
_debug( " Create Audio Streams \n ");
|
||||
//pa_stream_flags_t flag = PA_STREAM_AUTO_TIMING_UPDATE;
|
||||
pa_stream_flags_t flag = PA_STREAM_FIX_RATE;
|
||||
sample_spec.format = PA_SAMPLE_S16LE;
|
||||
sample_spec.rate = 44100;
|
||||
sample_spec.channels = 1;
|
||||
channel_map.channels = 1;
|
||||
|
||||
if( !pa_sample_spec_valid( &sample_spec ) ){
|
||||
_debug("Invalid sample specifications\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(!(playback = pa_stream_new( c, "SFLphone out" , &sample_spec, &channel_map))){
|
||||
_debug("Playback: pa_stream_new() failed : %s\n" , pa_strerror( pa_context_errno( c)));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(!(record = pa_stream_new( c, "SFLphone Mic" , &sample_spec, &channel_map))){
|
||||
_debug("Capture: pa_stream_new() failed : %s\n" , pa_strerror( pa_context_errno( c)));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
assert(playback);
|
||||
assert(record);
|
||||
assert(m);
|
||||
|
||||
// Set up the parameters required to open a (Callback)Stream:
|
||||
|
||||
pa_stream_connect_playback( playback, NULL , NULL , flag , NULL, NULL );
|
||||
pa_stream_set_state_callback(playback, stream_state_callback, NULL);
|
||||
// Transferring Data - Asynchronous Mode
|
||||
pa_stream_set_write_callback(playback, audioCallback, this);
|
||||
playback = new AudioStream(c, PLAYBACK_STREAM, "SFLphone out");
|
||||
pa_stream_set_write_callback( playback->pulseStream() , audioCallback, this);
|
||||
record = new AudioStream(c, CAPTURE_STREAM, "SFLphone in");
|
||||
pa_stream_set_read_callback( record->pulseStream() , audioCallback, this);
|
||||
//cache = new AudioStream(c, UPLOAD_STREAM, "Cache samples");
|
||||
|
||||
pa_threaded_mainloop_signal(m , 0);
|
||||
|
||||
pa_stream_set_state_callback(record, stream_state_callback, NULL);
|
||||
// Transferring Data - Asynchronous Mode
|
||||
pa_stream_set_read_callback(record, audioCallback, this);
|
||||
pa_stream_connect_record( record, NULL , NULL , flag );
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
@ -223,7 +156,6 @@ PulseLayer::putMain(void* buffer, int toCopy)
|
||||
_debug("Chopping sound, Ouch! RingBuffer full ?\n");
|
||||
return _mainSndRingBuffer.Put(buffer, a, 100);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -235,6 +167,13 @@ PulseLayer::flushMain()
|
||||
int
|
||||
PulseLayer::putUrgent(void* buffer, int toCopy)
|
||||
{
|
||||
int a = _urgentRingBuffer.AvailForPut();
|
||||
if ( a >= toCopy ) {
|
||||
return _urgentRingBuffer.Put(buffer, toCopy, 100 );
|
||||
} else {
|
||||
return _urgentRingBuffer.Put(buffer, a, 100 );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
@ -254,23 +193,22 @@ PulseLayer::flushMic()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
/* bool
|
||||
PulseLayer::isStreamStopped (void)
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
void
|
||||
PulseLayer::startStream (void)
|
||||
{
|
||||
_debug("Start stream\n");
|
||||
//pa_stream_cork( playback , 0, NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
PulseLayer::stopStream (void)
|
||||
{
|
||||
_debug("Stop stream\n");
|
||||
pa_stream_drop( playback );
|
||||
//pa_stream_drop( playback );
|
||||
}
|
||||
|
||||
bool
|
||||
@ -281,67 +219,47 @@ PulseLayer::isStreamActive (void)
|
||||
void
|
||||
PulseLayer::audioCallback ( pa_stream* s, size_t bytes, void* userdata )
|
||||
{
|
||||
pa_threaded_mainloop_signal( m , 0);
|
||||
|
||||
assert( s && bytes );
|
||||
|
||||
PulseLayer* pulse = (PulseLayer*) userdata;
|
||||
assert( s && bytes );
|
||||
pulse->write();
|
||||
//if(pa_stream_get_state(s) == PA_STREAM_READY )
|
||||
//{
|
||||
//if( bytes > 0 ){
|
||||
// pa_stream_write( s, user_data, bytes, pa_xfree, 0, PA_SEEK_RELATIVE );
|
||||
//}
|
||||
//}
|
||||
// pa_stream_write
|
||||
// // pa_stream_peek ( to read the next fragment from the buffer ) / pa_stream_drop( to remove the data from the buffer )
|
||||
//
|
||||
// int toPut;
|
||||
// int urgentAvail; // number of data right and data left
|
||||
// int micAvailPut;
|
||||
//
|
||||
// // AvailForGet tell the number of chars inside the buffer
|
||||
// // framePerBuffer are the number of data for one channel (left)
|
||||
// urgentAvail = _urgentRingBuffer.AvailForGet();
|
||||
// if (urgentAvail > 0) {
|
||||
// // Urgent data (dtmf, incoming call signal) come first.
|
||||
// toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof(SFLDataFormat);
|
||||
// _urgentRingBuffer.Get(out, toGet, spkrVolume);
|
||||
// // Consume the regular one as well (same amount of bytes)
|
||||
// _mainSndRingBuffer.Discard(toGet);
|
||||
// } else {
|
||||
// AudioLoop* tone = _manager->getTelephoneTone();
|
||||
// if ( tone != 0) {
|
||||
// tone->getNext(out, framesPerBuffer, spkrVolume);
|
||||
// } else if ( (tone=_manager->getTelephoneFile()) != 0 ) {
|
||||
// tone->getNext(out, framesPerBuffer, spkrVolume);
|
||||
// } else {
|
||||
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Additionally handle the mic's audio stream
|
||||
// micAvailPut = _micRingBuffer.AvailForPut();
|
||||
// toPut = (micAvailPut <= (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? micAvailPut : framesPerBuffer * sizeof(SFLDataFormat);
|
||||
// //_debug("AL: Nb sample: %d char, [0]=%f [1]=%f [2]=%f\n", toPut, in[0], in[1], in[2]);
|
||||
// _micRingBuffer.Put(in, toPut, micVolume);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
PulseLayer::write( void )
|
||||
{
|
||||
int toGet;
|
||||
int urgentAvail; // number of data right and data left
|
||||
int normalAvail; // number of data right and data left
|
||||
SFLDataFormat* out = (SFLDataFormat*)malloc(framesPerBuffer * sizeof(SFLDataFormat));
|
||||
normalAvail = _mainSndRingBuffer.AvailForGet();
|
||||
toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat);
|
||||
if (toGet) {
|
||||
_mainSndRingBuffer.Get(out, toGet, 100);
|
||||
_debug("Write %i bytes\n" , toGet);
|
||||
pa_stream_write( playback , out , toGet , pa_xfree, 0 , PA_SEEK_RELATIVE);
|
||||
urgentAvail = _urgentRingBuffer.AvailForGet();
|
||||
if (urgentAvail > 0) {
|
||||
// Urgent data (dtmf, incoming call signal) come first.
|
||||
_debug("Play urgent!\n");
|
||||
toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof(SFLDataFormat);
|
||||
_urgentRingBuffer.Get(out, toGet, 100);
|
||||
// Consume the regular one as well (same amount of bytes)
|
||||
_mainSndRingBuffer.Discard(toGet);
|
||||
} else {
|
||||
bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AudioLoop* tone = _manager->getTelephoneTone();
|
||||
if ( tone != 0) {
|
||||
tone->getNext(out, framesPerBuffer, 100);
|
||||
toGet = framesPerBuffer;
|
||||
} else if ( (tone=_manager->getTelephoneFile()) != 0 ) {
|
||||
tone->getNext(out, framesPerBuffer, 100);
|
||||
toGet = framesPerBuffer;
|
||||
} else {
|
||||
normalAvail = _mainSndRingBuffer.AvailForGet();
|
||||
toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat);
|
||||
if (toGet) {
|
||||
_mainSndRingBuffer.Get(out, toGet, 100);
|
||||
_debug("Write %i bytes\n" , toGet);
|
||||
_mainSndRingBuffer.Discard(toGet);
|
||||
} else {
|
||||
bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
|
||||
}
|
||||
}
|
||||
}
|
||||
pa_stream_write( playback->pulseStream() , out , toGet , pa_xfree, 0 , PA_SEEK_RELATIVE);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define _PULSE_LAYER_H
|
||||
|
||||
#include "audiolayer.h"
|
||||
#include "audiostream.h"
|
||||
|
||||
class RingBuffer;
|
||||
class ManagerImpl;
|
||||
@ -48,8 +49,6 @@ class PulseLayer : public AudioLayer {
|
||||
|
||||
void startStream(void);
|
||||
void stopStream(void);
|
||||
bool isStreamActive(void);
|
||||
bool isStreamStopped(void);
|
||||
|
||||
/**
|
||||
* Check if the capture is running
|
||||
@ -57,6 +56,7 @@ class PulseLayer : public AudioLayer {
|
||||
* false otherwise
|
||||
*/
|
||||
bool isCaptureActive( void ) { return true; }
|
||||
bool isStreamActive (void);
|
||||
|
||||
void flushMain();
|
||||
int putMain(void* buffer, int toCopy);
|
||||
@ -76,7 +76,6 @@ class PulseLayer : public AudioLayer {
|
||||
|
||||
static void audioCallback ( pa_stream* s, size_t bytes, void* userdata );
|
||||
|
||||
static void stream_state_callback( pa_stream* s, void* user_data );
|
||||
static void context_state_callback( pa_context* c, void* user_data );
|
||||
|
||||
/**
|
||||
@ -117,6 +116,8 @@ class PulseLayer : public AudioLayer {
|
||||
*/
|
||||
std::string getAudioPlugin( void ) { return "default"; }
|
||||
|
||||
//pa_stream* getCacheStream( void ) { return caching; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Drop the pending frames and close the capture device
|
||||
@ -132,10 +133,17 @@ class PulseLayer : public AudioLayer {
|
||||
|
||||
void connectPulseServer( void );
|
||||
|
||||
/** Ringbuffers for data */
|
||||
RingBuffer _mainSndRingBuffer;
|
||||
RingBuffer _urgentRingBuffer;
|
||||
|
||||
//pa_stream* playback;
|
||||
//pa_stream* record;
|
||||
/** PulseAudio streams and context */
|
||||
pa_context* context;
|
||||
pa_threaded_mainloop* m;
|
||||
|
||||
AudioStream* playback;
|
||||
AudioStream* record;
|
||||
AudioStream* cache;
|
||||
|
||||
};
|
||||
|
||||
|
37
src/audio/samplecache.cpp
Normal file
37
src/audio/samplecache.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <samplecache.h>
|
||||
|
||||
SampleCache::SampleCache( pa_stream* s )
|
||||
{
|
||||
_stream = s ;
|
||||
}
|
||||
|
||||
SampleCache::~SampleCache()
|
||||
{
|
||||
//delete _pulse;
|
||||
}
|
||||
|
||||
bool
|
||||
SampleCache::uploadSample( SFLDataFormat* buffer , size_t size )
|
||||
{
|
||||
//pa_stream_write( pulse->caching , buffer , size , pa_xfree, 0 , PA_SEEK_RELATIVE);
|
||||
//pa_stream_finish_upload( pulse->caching );
|
||||
}
|
41
src/audio/samplecache.h
Normal file
41
src/audio/samplecache.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@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
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SAMPLE_CACHE_H
|
||||
#define _SAMPLE_CACHE_H
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <audiolayer.h>
|
||||
|
||||
class SampleCache {
|
||||
|
||||
public:
|
||||
SampleCache( pa_stream* stream );
|
||||
~SampleCache();
|
||||
|
||||
bool uploadSample( SFLDataFormat* buffer, size_t size );
|
||||
bool removeSample( );
|
||||
bool isSampleCached( );
|
||||
|
||||
private:
|
||||
pa_stream* _stream;
|
||||
|
||||
};
|
||||
|
||||
#endif // _SAMPLE_CACHE_H
|
@ -124,7 +124,6 @@ typedef short int16;
|
||||
|
||||
#define ALSA 0
|
||||
#define PULSEAUDIO 1
|
||||
//#define AUDIODRIVER ALSA
|
||||
#define CHECK_INTERFACE( layer , api ) (layer == api)
|
||||
#define CHECK_INTERFACE( layer , api ) (layer != api)
|
||||
|
||||
#endif // __GLOBAL_H__
|
||||
|
@ -473,6 +473,7 @@ ManagerImpl::playDtmf(char code, bool isTalking)
|
||||
// numbers of int = length in milliseconds / 1000 (number of seconds)
|
||||
// = number of seconds * SAMPLING_RATE by SECONDS
|
||||
AudioLayer* audiolayer = getAudioDriver();
|
||||
int layer = audiolayer->getLayerType();
|
||||
|
||||
// fast return, no sound, so no dtmf
|
||||
if (audiolayer==0 || _dtmfKey == 0) { return false; }
|
||||
@ -496,7 +497,13 @@ ManagerImpl::playDtmf(char code, bool isTalking)
|
||||
// Put buffer to urgentRingBuffer
|
||||
// put the size in bytes...
|
||||
// so size * 1 channel (mono) * sizeof (bytes for the data)
|
||||
#if CHECK_INTERFACE( layer , ALSA )
|
||||
_debug("%i No good\n", layer);
|
||||
audiolayer->playSamples(_buf, size * sizeof(SFLDataFormat), isTalking);
|
||||
#else
|
||||
_debug("%i Good\n" , layer);
|
||||
audiolayer->putUrgent( _buf, size * sizeof(SFLDataFormat) );
|
||||
#endif
|
||||
}
|
||||
returnValue = true;
|
||||
|
||||
@ -822,13 +829,14 @@ ManagerImpl::ringtone()
|
||||
_audiofile.start();
|
||||
_toneMutex.leaveMutex();
|
||||
#if CHECK_INTERFACE( layer, ALSA )
|
||||
_debug()
|
||||
int size = _audiofile.getSize();
|
||||
SFLDataFormat output[ size ];
|
||||
_audiofile.getNext(output, size , 100);
|
||||
audiolayer->putUrgent( output , size );
|
||||
#else
|
||||
// pulseaudio code
|
||||
startStream();
|
||||
audiolayer->startStream();
|
||||
#endif
|
||||
} else {
|
||||
ringback();
|
||||
@ -1491,7 +1499,6 @@ ManagerImpl::selectAudioDriver (void)
|
||||
int layer = _audiodriver->getLayerType();
|
||||
_debug("Audio layer type: %i\n" , layer);
|
||||
|
||||
#if CHECK_INTERFACE( layer , ALSA )
|
||||
std::string alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
|
||||
int numCardIn = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
|
||||
int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
|
||||
@ -1514,13 +1521,15 @@ ManagerImpl::selectAudioDriver (void)
|
||||
setConfig( AUDIO , ALSA_CARD_ID_OUT , ALSA_DFT_CARD_ID );
|
||||
}
|
||||
|
||||
#if CHECK_INTERFACE( layer , ALSA )
|
||||
_debug("No good\n");
|
||||
_debugInit(" AudioLayer Opening Device");
|
||||
_audiodriver->setErrorMessage(-1);
|
||||
_audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin );
|
||||
if( _audiodriver -> getErrorMessage() != -1 )
|
||||
notifyErrClient( _audiodriver -> getErrorMessage());
|
||||
#else
|
||||
|
||||
_debug("Good\n");
|
||||
_debug(" Pulse audio driver \n");
|
||||
_audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin );
|
||||
if( _audiodriver -> getErrorMessage() != -1 )
|
||||
|
Reference in New Issue
Block a user