Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
savoirfairelinux
jami-daemon
Commits
41402c75
Commit
41402c75
authored
Sep 01, 2011
by
Tristan Matthews
Browse files
Merge branch 'master' of
git+ssh://git.sflphone.org/var/repos/sflphone/git/sflphone
parents
6f6b2c0c
11b168e7
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
daemon/src/audio/alsa/alsalayer.cpp
View file @
41402c75
...
...
@@ -89,7 +89,6 @@ AlsaLayer::AlsaLayer ()
,
is_capture_running_
(
false
)
,
is_playback_open_
(
false
)
,
is_capture_open_
(
false
)
,
trigger_request_
(
false
)
,
audioThread_
(
NULL
)
{
}
...
...
@@ -427,40 +426,44 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle)
}
//TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready
int
void
AlsaLayer
::
write
(
void
*
buffer
,
int
length
,
snd_pcm_t
*
handle
)
{
if
(
trigger_request_
)
{
trigger_request_
=
false
;
startPlaybackStream
();
}
snd_pcm_uframes_t
frames
=
snd_pcm_bytes_to_frames
(
handle
,
length
);
int
err
;
if
((
err
=
snd_pcm_writei
(
handle
,
buffer
,
frames
))
<
0
)
{
switch
(
err
)
{
case
-
EPIPE
:
case
-
ESTRPIPE
:
case
-
EIO
:
handle_xrun_playback
(
handle
);
if
(
snd_pcm_writei
(
handle
,
buffer
,
frames
)
<
0
)
_debug
(
"Audio: XRUN handling failed"
);
trigger_request_
=
true
;
int
err
=
snd_pcm_writei
(
handle
,
buffer
,
frames
);
if
(
err
>=
0
)
return
;
break
;
switch
(
err
)
{
case
-
EPIPE
:
case
-
ESTRPIPE
:
case
-
EIO
:
{
snd_pcm_status_t
*
status
;
snd_pcm_status_alloca
(
&
status
);
err
=
snd_pcm_status
(
handle
,
status
);
if
(
err
<
0
)
_error
(
"ALSA: Cannot get playback handle status (%s)"
,
snd_strerror
(
err
));
else
if
(
snd_pcm_status_get_state
(
status
)
==
SND_PCM_STATE_XRUN
)
{
stopPlaybackStream
();
preparePlaybackStream
();
startPlaybackStream
();
}
default:
_debug
(
"Audio: Write error unknown - dropping frames: %s"
,
snd_strerror
(
err
));
stopPlaybackStream
();
break
;
}
}
err
=
snd_pcm_writei
(
handle
,
buffer
,
frames
);
if
(
err
<
0
)
_error
(
"ALSA: XRUN handling failed : %s"
,
snd_strerror
(
err
));
break
;
}
return
(
err
>
0
)
?
err
:
0
;
default:
_error
(
"ALSA: unknown write error, dropping frames: %s"
,
snd_strerror
(
err
));
stopPlaybackStream
();
break
;
}
}
int
...
...
@@ -473,68 +476,43 @@ AlsaLayer::read (void* buffer, int toCopy)
snd_pcm_uframes_t
frames
=
snd_pcm_bytes_to_frames
(
captureHandle_
,
toCopy
);
int
err
;
if
((
err
=
snd_pcm_readi
(
captureHandle_
,
buffer
,
frames
))
<
0
)
{
switch
(
err
)
{
case
-
EPIPE
:
case
-
ESTRPIPE
:
case
-
EIO
:
_debug
(
"Audio: XRUN capture ignored (%s)"
,
snd_strerror
(
err
));
handle_xrun_capture
();
break
;
case
EPERM
:
_debug
(
"Audio: Capture EPERM (%s)"
,
snd_strerror
(
err
));
prepareCaptureStream
();
startCaptureStream
();
break
;
default:
break
;
}
return
0
;
}
return
toCopy
;
}
void
AlsaLayer
::
handle_xrun_capture
(
void
)
{
snd_pcm_status_t
*
status
;
snd_pcm_status_alloca
(
&
status
);
if
(
snd_pcm_status
(
captureHandle_
,
status
)
<=
0
)
{
if
(
snd_pcm_status_get_state
(
status
)
==
SND_PCM_STATE_XRUN
)
{
stopCaptureStream
();
prepareCaptureStream
();
startCaptureStream
();
}
}
else
_debug
(
"Audio: Get status failed"
);
}
int
err
=
snd_pcm_readi
(
captureHandle_
,
buffer
,
frames
);
if
(
err
>=
0
)
return
snd_pcm_frames_to_bytes
(
captureHandle_
,
frames
);
switch
(
err
)
{
case
-
EPIPE
:
case
-
ESTRPIPE
:
case
-
EIO
:
{
snd_pcm_status_t
*
status
;
snd_pcm_status_alloca
(
&
status
);
err
=
snd_pcm_status
(
captureHandle_
,
status
);
if
(
err
<
0
)
_error
(
"ALSA: Get status failed: %s"
,
snd_strerror
(
err
));
else
if
(
snd_pcm_status_get_state
(
status
)
==
SND_PCM_STATE_XRUN
)
{
stopCaptureStream
();
prepareCaptureStream
();
startCaptureStream
();
}
void
AlsaLayer
::
handle_xrun_playback
(
snd_pcm_t
*
handle
)
{
snd_pcm_status_t
*
status
;
snd_pcm_status_alloca
(
&
status
);
_error
(
"ALSA: XRUN capture ignored (%s)"
,
snd_strerror
(
err
));
break
;
}
int
state
;
if
((
state
=
snd_pcm_status
(
handle
,
status
))
<
0
)
_debug
(
"Audio: Error: Cannot get playback handle status (%s)"
,
snd_strerror
(
state
)
);
else
{
int
state
=
snd_pcm_status_get_state
(
status
)
;
case
EPERM
:
_error
(
"ALSA: Can't capture, EPERM (%s)"
,
snd_strerror
(
err
));
prepareCaptureStream
(
);
startCaptureStream
();
break
;
if
(
state
==
SND_PCM_STATE_XRUN
)
{
stopPlaybackStream
()
;
preparePlaybackStream
();
default:
break
;
}
trigger_request_
=
true
;
}
}
return
0
;
}
std
::
string
...
...
@@ -645,33 +623,122 @@ namespace
}
}
void
AlsaLayer
::
audioCallback
(
void
)
void
AlsaLayer
::
capture
(
void
)
{
unsigned
int
mainBufferSampleRate
=
getMainBuffer
()
->
getInternalSamplingRate
();
bool
resample
=
audioSampleRate_
!=
mainBufferSampleRate
;
notifyincomingCall
();
int
toGetSamples
=
snd_pcm_avail_update
(
captureHandle_
);
if
(
toGetSamples
<
0
)
_error
(
"Audio: Mic error: %s"
,
snd_strerror
(
toGetSamples
));
if
(
toGetSamples
<=
0
)
return
;
const
int
framesPerBufferAlsa
=
2048
;
if
(
toGetSamples
>
framesPerBufferAlsa
)
toGetSamples
=
framesPerBufferAlsa
;
int
toGetBytes
=
toGetSamples
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
in
=
(
SFLDataFormat
*
)
malloc
(
toGetBytes
);
if
(
read
(
in
,
toGetBytes
)
!=
toGetBytes
)
{
_error
(
"ALSA MIC : Couldn't read!"
);
goto
end
;
}
adjustVolume
(
in
,
toGetSamples
,
Manager
::
instance
().
getSpkrVolume
());
if
(
resample
)
{
int
outSamples
=
toGetSamples
*
((
double
)
audioSampleRate_
/
mainBufferSampleRate
);
int
outBytes
=
outSamples
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
rsmpl_out
=
(
SFLDataFormat
*
)
malloc
(
outBytes
);
converter_
->
resample
(
(
SFLDataFormat
*
)
in
,
rsmpl_out
,
mainBufferSampleRate
,
audioSampleRate_
,
toGetSamples
);
dcblocker_
.
process
(
rsmpl_out
,
outBytes
);
getMainBuffer
()
->
putData
(
rsmpl_out
,
outBytes
);
free
(
rsmpl_out
);
}
else
{
SFLDataFormat
*
filter_out
=
(
SFLDataFormat
*
)
malloc
(
toGetBytes
);
dcblocker_
.
process
(
in
,
filter_out
,
toGetBytes
);
getMainBuffer
()
->
putData
(
filter_out
,
toGetBytes
);
free
(
filter_out
);
}
end:
free
(
in
);
}
void
AlsaLayer
::
playback
(
int
maxSamples
)
{
unsigned
short
spkrVolume
=
Manager
::
instance
().
getSpkrVolume
();
AudioLoop
*
tone
=
Manager
::
instance
().
getTelephoneTone
();
AudioLoop
*
file_tone
=
Manager
::
instance
().
getTelephoneFile
();
unsigned
int
mainBufferSampleRate
=
getMainBuffer
()
->
getInternalSamplingRate
();
bool
resample
=
audioSampleRate_
!=
mainBufferSampleRate
;
int
toGet
=
getMainBuffer
()
->
availForGet
();
int
toPut
=
maxSamples
*
sizeof
(
SFLDataFormat
);
if
(
toGet
<=
0
)
{
// no audio available, play tone or silence
AudioLoop
*
tone
=
Manager
::
instance
().
getTelephoneTone
();
AudioLoop
*
file_tone
=
Manager
::
instance
().
getTelephoneFile
();
// AvailForGet tell the number of chars inside the buffer
// framePerBuffer are the number of data for one channel (left)
int
urgentAvailBytes
=
urgentRingBuffer_
.
AvailForGet
();
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
toPut
);
if
(
tone
)
tone
->
getNext
(
out
,
maxSamples
,
spkrVolume
);
else
if
(
file_tone
&&
!
ringtoneHandle_
)
file_tone
->
getNext
(
out
,
maxSamples
,
spkrVolume
);
else
memset
(
out
,
0
,
toPut
);
write
(
out
,
toPut
,
playbackHandle_
);
free
(
out
);
return
;
}
// play the regular sound samples
int
maxNbBytesToGet
=
toPut
;
// Compute maximal value to get from the ring buffer
double
resampleFactor
=
1.0
;
if
(
resample
)
{
resampleFactor
=
(
double
)
audioSampleRate_
/
mainBufferSampleRate
;
maxNbBytesToGet
=
(
double
)
toGet
/
resampleFactor
;
}
if
(
toGet
>
maxNbBytesToGet
)
toGet
=
maxNbBytesToGet
;
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
toGet
);
getMainBuffer
()
->
getData
(
out
,
toGet
);
adjustVolume
(
out
,
toGet
/
sizeof
(
SFLDataFormat
),
spkrVolume
);
if
(
resample
)
{
int
inSamples
=
toGet
/
sizeof
(
SFLDataFormat
);
int
outSamples
=
inSamples
*
resampleFactor
;
SFLDataFormat
*
rsmpl_out
=
(
SFLDataFormat
*
)
malloc
(
outSamples
*
sizeof
(
SFLDataFormat
));
converter_
->
resample
(
out
,
rsmpl_out
,
mainBufferSampleRate
,
audioSampleRate_
,
inSamples
);
write
(
rsmpl_out
,
outSamples
*
sizeof
(
SFLDataFormat
),
playbackHandle_
);
free
(
rsmpl_out
);
}
else
{
write
(
out
,
toGet
,
playbackHandle_
);
}
free
(
out
);
}
void
AlsaLayer
::
audioCallback
(
void
)
{
if
(
!
playbackHandle_
or
!
captureHandle_
)
return
;
notifyincomingCall
();
unsigned
short
spkrVolume
=
Manager
::
instance
().
getSpkrVolume
();
snd_pcm_wait
(
playbackHandle_
,
20
);
int
playbackAvailSmpl
=
snd_pcm_avail_update
(
playbackHandle_
);
int
playbackAvailBytes
=
playbackAvailSmpl
*
sizeof
(
SFLDataFormat
);
if
(
urgentAvailBytes
>
0
)
{
int
toGet
=
urgentRingBuffer_
.
AvailForGet
();
if
(
toGet
>
0
)
{
// Urgent data (dtmf, incoming call signal) come first.
int
toGet
=
urgentAvailBytes
;
if
(
toGet
>
playbackAvailBytes
)
toGet
=
playbackAvailBytes
;
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
toGet
);
...
...
@@ -684,109 +751,26 @@ void AlsaLayer::audioCallback (void)
getMainBuffer
()
->
discard
(
toGet
);
}
else
{
// regular audio data
int
toGet
=
getMainBuffer
()
->
availForGet
();
if
(
toGet
<=
0
)
{
// no audio available, play tone or silence
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
playbackAvailBytes
);
if
(
tone
)
tone
->
getNext
(
out
,
playbackAvailSmpl
,
spkrVolume
);
else
if
(
file_tone
&&
!
ringtoneHandle_
)
file_tone
->
getNext
(
out
,
playbackAvailSmpl
,
spkrVolume
);
else
memset
(
out
,
0
,
playbackAvailBytes
);
write
(
out
,
playbackAvailBytes
,
playbackHandle_
);
free
(
out
);
}
else
{
// play the regular sound samples
int
maxNbBytesToGet
=
playbackAvailBytes
;
// Compute maximal value to get from the ring buffer
double
resampleFactor
=
1.0
;
if
(
resample
)
{
resampleFactor
=
(
double
)
audioSampleRate_
/
mainBufferSampleRate
;
maxNbBytesToGet
=
(
double
)
toGet
/
resampleFactor
;
}
if
(
toGet
>
maxNbBytesToGet
)
toGet
=
maxNbBytesToGet
;
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
toGet
);
getMainBuffer
()
->
getData
(
out
,
toGet
);
adjustVolume
(
out
,
toGet
/
sizeof
(
SFLDataFormat
),
spkrVolume
);
if
(
resample
)
{
int
inSamples
=
toGet
/
sizeof
(
SFLDataFormat
);
int
outSamples
=
inSamples
*
resampleFactor
;
SFLDataFormat
*
rsmpl_out
=
(
SFLDataFormat
*
)
malloc
(
outSamples
*
sizeof
(
SFLDataFormat
));
converter_
->
resample
(
out
,
rsmpl_out
,
mainBufferSampleRate
,
audioSampleRate_
,
inSamples
);
write
(
rsmpl_out
,
outSamples
*
sizeof
(
SFLDataFormat
),
playbackHandle_
);
free
(
rsmpl_out
);
}
else
{
write
(
out
,
toGet
,
playbackHandle_
);
}
free
(
out
);
}
playback
(
playbackAvailSmpl
);
}
if
(
file_tone
and
ringtoneHandle_
)
{
int
ringtoneAvailSmpl
=
snd_pcm_avail_update
(
ringtoneHandle_
);
int
ringtoneAvailBytes
=
ringtoneAvailSmpl
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
ringtoneAvailBytes
);
file_tone
->
getNext
(
out
,
ringtoneAvailSmpl
,
spkrVolume
);
write
(
out
,
ringtoneAvailBytes
,
ringtoneHandle_
);
free
(
out
);
}
else
if
(
ringtoneHandle_
)
{
int
ringtoneAvailSmpl
=
snd_pcm_avail_update
(
ringtoneHandle_
);
int
ringtoneAvailBytes
=
ringtoneAvailSmpl
*
sizeof
(
SFLDataFormat
);
if
(
ringtoneHandle_
)
{
AudioLoop
*
file_tone
=
Manager
::
instance
().
getTelephoneFile
();
int
ringtoneAvailSmpl
=
snd_pcm_avail_update
(
ringtoneHandle_
);
int
ringtoneAvailBytes
=
ringtoneAvailSmpl
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
ringtoneAvailBytes
);
memset
(
out
,
0
,
ringtoneAvailBytes
);
write
(
out
,
ringtoneAvailBytes
,
ringtoneHandle_
);
free
(
out
);
}
SFLDataFormat
*
out
=
(
SFLDataFormat
*
)
malloc
(
ringtoneAvailBytes
);
// Additionally handle the mic's audio stream
if
(
!
is_capture_running_
)
return
;
if
(
file_tone
)
file_tone
->
getNext
(
out
,
ringtoneAvailSmpl
,
spkrVolume
);
else
memset
(
out
,
0
,
ringtoneAvailBytes
);
int
toPutSamples
=
snd_pcm_avail_update
(
captureHandle_
);
if
(
toPutSamples
<=
0
)
{
if
(
toPutSamples
<
0
)
_error
(
"Audio: Mic error: %s"
,
snd_strerror
(
toPutSamples
));
return
;
}
const
int
framesPerBufferAlsa
=
2048
;
if
(
toPutSamples
>
framesPerBufferAlsa
)
toPutSamples
=
framesPerBufferAlsa
;
int
toPutBytes
=
toPutSamples
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
in
=
(
SFLDataFormat
*
)
malloc
(
toPutBytes
);
int
bytes
=
read
(
in
,
toPutBytes
);
if
(
toPutBytes
!=
bytes
)
{
_error
(
"ALSA MIC : Couldn't read!"
);
free
(
in
);
return
;
write
(
out
,
ringtoneAvailBytes
,
ringtoneHandle_
);
free
(
out
);
}
adjustVolume
(
in
,
toPutSamples
,
spkrVolume
);
if
(
resample
)
{
int
outSamples
=
toPutSamples
*
((
double
)
audioSampleRate_
/
mainBufferSampleRate
);
int
outBytes
=
outSamples
*
sizeof
(
SFLDataFormat
);
SFLDataFormat
*
rsmpl_out
=
(
SFLDataFormat
*
)
malloc
(
outBytes
);
converter_
->
resample
(
(
SFLDataFormat
*
)
in
,
rsmpl_out
,
mainBufferSampleRate
,
audioSampleRate_
,
toPutSamples
);
dcblocker_
.
process
(
rsmpl_out
,
outBytes
);
getMainBuffer
()
->
putData
(
rsmpl_out
,
outBytes
);
free
(
rsmpl_out
);
}
else
{
SFLDataFormat
*
filter_out
=
(
SFLDataFormat
*
)
malloc
(
toPutBytes
);
dcblocker_
.
process
(
in
,
filter_out
,
toPutBytes
);
getMainBuffer
()
->
putData
(
filter_out
,
toPutBytes
);
free
(
filter_out
);
}
free
(
in
);
// Additionally handle the mic's audio stream
if
(
is_capture_running_
)
capture
();
}
daemon/src/audio/alsa/alsalayer.h
View file @
41402c75
...
...
@@ -124,6 +124,9 @@ class AlsaLayer : public AudioLayer
return
audioPlugin_
;
}
void
playback
(
int
maxSamples
);
void
capture
(
void
);
void
audioCallback
(
void
);
/**
...
...
@@ -204,9 +207,8 @@ class AlsaLayer : public AudioLayer
* ALSA Library API
* @param buffer The data to be copied
* @param length The size of the buffer
* @return int The number of frames actually copied
*/
int
write
(
void
*
buffer
,
int
length
,
snd_pcm_t
*
handle
);
void
write
(
void
*
buffer
,
int
length
,
snd_pcm_t
*
handle
);
/**
* Read data from the internal ring buffer
...
...
@@ -217,18 +219,6 @@ class AlsaLayer : public AudioLayer
*/
int
read
(
void
*
buffer
,
int
toCopy
);
/**
* Recover from XRUN state for capture
* ALSA Library API
*/
void
handle_xrun_capture
(
void
);
/**
* Recover from XRUN state for playback
* ALSA Library API
*/
void
handle_xrun_playback
(
snd_pcm_t
*
handle
);
/**
* Handles to manipulate playback stream
* ALSA Library API
...
...
@@ -266,7 +256,6 @@ class AlsaLayer : public AudioLayer
bool
is_capture_running_
;
bool
is_playback_open_
;
bool
is_capture_open_
;
bool
trigger_request_
;
AlsaThread
*
audioThread_
;
};
...
...
daemon/src/audio/dcblocker.cpp
View file @
41402c75
...
...
@@ -51,20 +51,7 @@ int DcBlocker::getData (SFLDataFormat *outputData UNUSED)
void
DcBlocker
::
process
(
SFLDataFormat
*
data
,
int
nbBytes
)
{
// y(n) = x(n) - x(n-1) + R y(n-1) , R = 0.9999
int
nbSamples
=
nbBytes
/
sizeof
(
SFLDataFormat
);
for
(
int
i
=
0
;
i
<
nbSamples
;
i
++
)
{
_x
=
data
[
i
];
_y
=
(
SFLDataFormat
)
(
(
float
)
_x
-
(
float
)
_xm1
+
0.995
*
(
float
)
_ym1
);
_xm1
=
_x
;
_ym1
=
_y
;
data
[
i
]
=
_y
;
}
abort
();
// use the 3 args prototype with input == output
}
int
DcBlocker
::
process
(
SFLDataFormat
*
inputData
,
SFLDataFormat
*
outputData
,
int
nbBytes
)
...
...
daemon/src/audio/dcblocker.h
View file @
41402c75
...
...
@@ -57,16 +57,7 @@ class DcBlocker : public Algorithm
*/
virtual
int
getData
(
SFLDataFormat
*
outputData
);
/**
* Perform dc blocking given the input data
*/
virtual
void
process
(
SFLDataFormat
*
data
,
int
nbBytes
);
/**
* Perform echo cancellation using internal buffers
* \param inputData containing mixed echo and voice data
* \param outputData containing
*/
virtual
void
process
(
SFLDataFormat
*
inputData
,
int
nbBytes
);
virtual
int
process
(
SFLDataFormat
*
inputData
,
SFLDataFormat
*
outputData
,
int
nbBytes
);
private:
...
...
daemon/src/audio/pulseaudio/audiostream.cpp
View file @
41402c75
...
...
@@ -31,247 +31,106 @@
#include
<audiostream.h>
#include
"pulselayer.h"
static
pa_channel_map
channel_map
;
AudioStream
::
AudioStream
(
pa_context
*
c
,
pa_threaded_mainloop
*
m
,
std
::
string
desc
,
int
type
,
int
smplrate
)
:
_audiostream
(
NULL
),
_context
(
c
),
_streamType
(
type
),
_streamDescription
(
desc
),
_volume
(),
_flag
(
PA_STREAM_AUTO_TIMING_UPDATE
),
_sample_spec
(),
_mainloop
(
m
)
{
_sample_spec
.
format
=
PA_SAMPLE_S16LE
;
// PA_SAMPLE_FLOAT32LE;
_sample_spec
.
rate
=
smplrate
;
_sample_spec
.
channels
=
1
;
channel_map
.
channels
=
1
;
pa_cvolume_set
(
&
_volume
,
1
,
PA_VOLUME_NORM
)
;
// * vol / 100 ;
}
AudioStream
::~
AudioStream
()
{
disconnectStream
();
}
bool
AudioStream
::
connectStream
(
std
::
string
*
deviceName
)
{
ost
::
MutexLock
guard
(
_mutex
);
if
(
!
_audiostream
)
_audiostream
=
createStream
(
_context
,
deviceName
);
return
true
;
}
static
void
success_cb
(
pa_stream
*
s
,
int
success
UNUSED
,
void
*
userdata
)
AudioStream
::
AudioStream
(
pa_context
*
c
,
pa_threaded_mainloop
*
m
,
const
char
*
desc
,
int
type
,
int
smplrate
,
std
::
string
*
deviceName
)
:
_mainloop
(
m
)
{
static
const
pa_channel_map
channel_map
=
{
1
,
{
PA_CHANNEL_POSITION_MONO
},
};
pa_sample_spec
sample_spec
=
{
PA_SAMPLE_S16LE
,
// PA_SAMPLE_FLOAT32LE,
smplrate
,
1
};
assert
(
pa_sample_spec_valid
(
&
sample_spec
));
assert
(
pa_channel_map_valid
(
&
channel_map
));
assert
(
s
);
pa_threaded_mainloop
*
mainloop
=
(
pa_threaded_mainloop
*
)
userdata
;
_audiostream
=
pa_stream_new
(
c
,
desc
,
&
sample_spec
,
&
channel_map
);
if
(
!
_audiostream
)
{
_error
(
"Pulse: %s: pa_stream_new() failed : %s"
,
desc
,
pa_strerror
(
pa_context_errno
(
c
)));
throw
std
::
runtime_error
(
"Pulse : could not create stream
\n
"
);
}
pa_threaded_mainloop_signal
(
mainloop
,
0
);
}
pa_buffer_attr
attributes
;
attributes
.
maxlength
=
pa_usec_to_bytes
(
160
*
PA_USEC_PER_MSEC
,
&
sample_spec
);
attributes
.
tlength
=
pa_usec_to_bytes
(
80
*
PA_USEC_PER_MSEC
,
&
sample_spec
);
attributes
.
prebuf
=
0
;
attributes
.
fragsize
=
pa_usec_to_bytes
(
80
*
PA_USEC_PER_MSEC
,
&
sample_spec
);
attributes
.
minreq
=
(
uint32_t
)
-
1
;
bool
AudioStream
::
drainStream
(
void
)