I'm struggling to understand what I'm doing wrong in my audio playback routine.
I've a thread that takes buffers from other threads and plays them the same way this alsa example program does: https://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html
I'm referring to the write_loop() function. This is the device configuration setup up of the pcm.c example program (output of snd_pcm_dump()):
ALSA <-> PulseAudio PCM I/O Plugin
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 44100
exact rate : 44100 (44100/1)
msbits : 16
buffer_size : 22050
period_size : 4410
period_time : 100000
tstamp_mode : NONE
tstamp_type : GETTIMEOFDAY
period_step : 1
avail_min : 4410
period_event : 0
start_threshold : 22050
stop_threshold : 22050
silence_threshold: 0
silence_size : 0
boundary : 6206523236469964800
What I see placing some printf() around snd_pcm_writei() is that it gets executed 5 times straight and every next loop snd_pcm_writei() takes 100ms to complete. This is exactly what I was expecting to see.
This is device setup of my program:
ALSA <-> PulseAudio PCM I/O Plugin
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : FLOAT_LE
subformat : STD
channels : 1
rate : 44100
exact rate : 44100 (44100/1)
msbits : 32
buffer_size : 13230
period_size : 4410
period_time : 100000
tstamp_mode : NONE
tstamp_type : GETTIMEOFDAY
period_step : 1
avail_min : 4410
period_event : 0
start_threshold : 4410
stop_threshold : 13230
silence_threshold: 0
silence_size : 0
boundary : 7447827883763957760
What happens is snd_pcm_writei() runs 5 times (and this is ok) but after that every new loop it returns immediately with -EAGAIN. Retrying continuously for 100ms (100% cpu usage) to play the same buffer eventually it gets played, snd_pcm_writei() returns a positive number and for next audio buffer I get immediately -EAGAIN, for 100ms; and so on. The audio playback, however, is fine.
What I don't understand is why it doesn't wait 100ms to play the new buffer instead of returning immediately -EAGAIN (cannot find anything in ALSA docs about snd_pcm_writei() returning -EAGAIN).
Thanks in advance for any help!
A PCM device can be in blocking mode (waiting) or in non-blocking mode (returning -EAGAIN).
This mode can be set with a flag when calling snd_pcm_open(), or with snd_pcm_nonblock().
Related
I've set up a radio for local network, everything (Icecast2, BUTT (Broadcast Using This Tool)) is ready and working except one thing. BUTT intends to capture audio from input device, but that is not what I want, I want to stream desktop audio. I've created a loopback device using modprobe snd-aloop. I actually managed to route the audio from a specific program to that loopback device and I was able to hear it on the web player but the sound is stuttering, speeding up and getting back to normal its hard to describe. It's like decoder cannot catch up. All these are happening in less than a second.
Output from pactl list short sinks
1 alsa_output.pci-0000_00_1f.3.analog-stereo module-alsa-card.c s16le 2ch 48000Hz RUNNING
3 alsa_output.platform-snd_aloop.0.analog-stereo module-alsa-card.c s16le 2ch 44100Hz IDLE
11 alsa_output.pci-0000_01_00.1.hdmi-stereo module-alsa-card.c s16le 2ch 44100Hz IDLE
I have created ~/.asoundrc as most of the tutorial encouraged me to do so, and I believe this problem can be solved by this file but I am not familiar enough with alsa and its features. Sample rate of sound card is 48000 Hz but BUTT is forcing me to select 44100.
Contents of ~/.asoundrc
pcm.!default {
type asym
playback.pcm "LoopAndReal"
#capture.pcm "looprec"
capture.pcm "hw:0,0"
}
pcm.looprec {
type hw
card "Loopback"
device 1
subdevice 0
}
pcm.LoopAndReal {
type plug
slave.pcm mdev
route_policy "duplicate"
}
pcm.mdev {
type multi
slaves.a.pcm pcm.MixReale
slaves.a.channels 2
slaves.b.pcm pcm.MixLoopback
slaves.b.channels 2
bindings.0.slave a
bindings.0.channel 0
bindings.1.slave a
bindings.1.channel 1
bindings.2.slave b
bindings.2.channel 0
bindings.3.slave b
bindings.3.channel 1
}
pcm.MixReale {
type dmix
ipc_key 1024
slave {
pcm "hw:0,0"
#rate 48000
rate 44100
periods 128
period_time 0
period_size 1024 # must be power of 2
buffer_size 8192
}
}
pcm.MixLoopback {
type dmix
ipc_key 1025
slave {
pcm "hw:Loopback,0,0"
#rate 48000
rate 44100
periods 128
period_time 0
period_size 1024 # must be power of 2
buffer_size 8192
}
}
Thanks in advance for any help.
I've managed to pipe my desktop audio to mic input using purely pulse audio and no alsa, thanks to this thread: https://unix.stackexchange.com/questions/82259/how-to-pipe-audio-output-to-mic-input
I am facing an issue where the period size has been set to 128, still sometimes the polling starts late.
For this configuration, where the period size is set to 128 and rate is 16 Khz, therefore polling should occur after each 128/16 = 8 ms, but in some cases the polling occurs a bit late which causes certain issues in the application. Since, polling is triggered internally by Alsa system modules which is dependent on the configuration, kindly suggest if we are going wrong somewhere with the configuration or any similar issue anyone might have experienced. Pasting the PCM dump of my Setup below:-
APCM_DUMP_DEVICE_DETALS :-
Hardware PCM card 0 'mt2712-d1v1' device 5 subdevice 0
Its setup is:
stream : CAPTURE
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 16000
exact rate : 16000 (16000/1)
msbits : 16
buffer_size : 512
period_size : 128
period_time : 8000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 128
period_event : 0
start_threshold : 128
stop_threshold : 512
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
appl_ptr : 0
hw_ptr : 0
APCM_DUMP_DEVICE_DETALS :-
Hardware PCM card 0 'mt2712-d1v1' device 1 subdevice 0
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 16000
exact rate : 16000 (16000/1)
msbits : 16
buffer_size : 512
period_size : 128
period_time : 8000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 128
period_event : 0
start_threshold : 128
stop_threshold : 512
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
appl_ptr : 0
hw_ptr : 0
APCM_DUMP_DEVICE_DETALS :-
Hardware PCM card 0 'mt2712-d1v1' device 12 subdevice 0
Its setup is:
stream : CAPTURE
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 16000
exact rate : 16000 (16000/1)
msbits : 16
buffer_size : 512
period_size : 128
period_time : 8000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 128
period_event : 0
start_threshold : 128
stop_threshold : 512
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
appl_ptr : 0
hw_ptr : 0
APCM_DUMP_DEVICE_DETALS :-
Hardware PCM card 0 'mt2712-d1v1' device 11 subdevice 0
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 16000
exact rate : 16000 (16000/1)
msbits : 16
buffer_size : 512
period_size : 128
period_time : 8000
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 128
period_event : 0
start_threshold : 128
stop_threshold : 512
silence_threshold: 0
silence_size : 0
boundary : 4611686018427387904
appl_ptr : 0
hw_ptr : 0
For the issue, we tried to analyze the kernel traces, after going through the kernel traces, we found out that we were reading the entire available data (snd_pcm_avail_update) for the capture device(rather than the period_size), due to which a flag in kernel was set to 0 since it had 0 bytes available due to which it was missing the interrupt to wake up the read thread(application) in time. Once we set the pcm_read to read only the required data, the behaviour was rectified
I have a Debian machine (3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux) on which I have some audio devices connected. The devices that are stereo works well, but I have a problem with a mono headset. When I type the command
aplay -v -D plughw:2,0 ~/piano2.wav
the device waits up to 3-4 seconds before starting to output sound. If I retype the command in the following 5 seconds, the sound is played directly, but if I wait a bit more, I have to wait 3-4 seconds again before hearing anything.
Here is the output when I run the command above :
Playing WAVE '/home/console/piano2.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Plug PCM: Route conversion PCM (sformat=S16_LE)
Transformation table:
0 <- 0*0.5 + 1*0.5
Its setup is:
stream : PLAYBACK
access : RW_INTERLEAVED
format : S16_LE
subformat : STD
channels : 2
rate : 48000
exact rate : 48000 (48000/1)
msbits : 16
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: Rate conversion PCM (16000, sformat=S16_LE)
Converter: libspeex (builtin)
Protocol version: 10002
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 48000
exact rate : 48000 (48000/1)
msbits : 16
buffer_size : 24000
period_size : 6000
period_time : 125000
tstamp_mode : NONE
period_step : 1
avail_min : 6000
period_event : 0
start_threshold : 24000
stop_threshold : 24000
silence_threshold: 0
silence_size : 0
boundary : 6755399441055744000
Slave: Hardware PCM card 2 'Jabra PRO 9460' device 0 subdevice 0
Its setup is:
stream : PLAYBACK
access : MMAP_INTERLEAVED
format : S16_LE
subformat : STD
channels : 1
rate : 16000
exact rate : 16000 (16000/1)
msbits : 16
buffer_size : 8000
period_size : 2000
period_time : 125000
tstamp_mode : NONE
period_step : 1
avail_min : 2000
period_event : 0
start_threshold : 8000
stop_threshold : 8000
silence_threshold: 0
silence_size : 0
boundary : 9007199254740992000
appl_ptr : 0
hw_ptr : 0
And this is my .asoundrc file :
pcm.!default {
type plug
slave {
pcm "hw:0,0"
}
}
pcm.device1 {
type plug
slave {
pcm "hw:1,0"
}
}
pcm.device2 {
type plug
slave {
pcm "hw:2,0"
}
}
pcm.device3 {
type plug
slave {
pcm "hw:3,0"
}
}
ctl.!default {
type hw
card 0
}
ctl.device1 {
type hw
card 1
}
ctl.device2 {
type hw
card 2
}
ctl.device3 {
type hw
card 3
}
Does anybody have and idea why I get such a delay when my device wakes-up ?
Thanks
I am trying to mux video (H.264) and audio (PCM_S16LE, no compression) into an MPEG transport stream using ffmpeg. The video shows fine. The audio stream, however, does not play. The audio stream, shown by ffprobe is AAC, which is obviously not my intention. So I must be doing something wrong in adding the audio stream. Any idea how I can correct this?
This is my code for adding an audio stream:
void add_audio_stream()
{
CodecID codec_id = CODEC_ID_PCM_S16LE;
AVStream *p_ast = av_new_stream(fc, 1);
if (!p_ast) {
fprintf(stderr, "Could not alloc audio stream\n");
exit(1);
}
ai = p_ast->index;
AVCodecContext *pcc = p_ast->codec;
avcodec_get_context_defaults2( pcc, AVMEDIA_TYPE_AUDIO );
pcc->codec_type = AVMEDIA_TYPE_AUDIO;
pcc->codec_id = codec_id;
pcc->sample_fmt = AV_SAMPLE_FMT_S16;
//pcc->bit_rate = 44100*16*2;
pcc->bit_rate = 0;
pcc->sample_rate = 44100;
pcc->channels = 2;
pcc->time_base = (AVRational){1, 44100};
// some formats want stream headers to be separate
if (fc->oformat->flags & AVFMT_GLOBALHEADER)
{
printf(" **** 1 ****\n");
pcc->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
else
printf(" **** 2 ****\n");
AVCodec *codec;
/* find the audio encoder */
codec = avcodec_find_encoder(pcc->codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
/* open it */
if (avcodec_open(pcc, codec) < 0)
{
fprintf(stderr, "could not open codec\n");
exit(1);
}
}
Here is the output of ffprobe:
ffprobe version N-32405-g6337de9, Copyright (c) 2007-2011 the FFmpeg developers
built on Sep 8 2011 11:20:12 with gcc 4.4.3
configuration: --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libxvid --enable-x11grab --enable-libmp3lame
libavutil 51. 16. 0 / 51. 16. 0
libavcodec 53. 13. 0 / 53. 13. 0
libavformat 53. 12. 0 / 53. 12. 0
libavdevice 53. 3. 0 / 53. 3. 0
libavfilter 2. 39. 0 / 2. 39. 0
libswscale 2. 1. 0 / 2. 1. 0
libpostproc 51. 2. 0 / 51. 2. 0
[mpegts # 0xa96daa0] Continuity Check Failed
[mpegts # 0xa96daa0] Continuity Check Failed
[aac # 0xa974da0] channel element 0.1 is not allocated
[aac # 0xa974da0] More than one AAC RDB per ADTS frame is not implemented. Update your FFmpeg version to the newest one from Git. If the problem still occurs, it means that your file has a feature which has not been implemented.
.
.
lot of gobbly-gook about missing AAC parameters . . .
.
.
[aac # 0xa974da0] More than one AAC RDB per ADTS frame is not implemented. Update your FFmpeg version to the newest one from Git. If the problem still occurs, it means that your file has a feature which has not been implemented.
[aac # 0xa974da0] Error decoding AAC frame header.
[mpegts # 0xa96daa0] max_analyze_duration 5000000 reached at 5429789
[mpegts # 0xa96daa0] Continuity Check Failed
[mpegts # 0xa96daa0] Continuity Check Failed
Input #0, mpegts, from 'test_audio_video.mts':
Duration: 00:00:40.35, start: 0.010000, bitrate: 1907 kb/s
Program 1
Metadata:
service_name : Service01
service_provider: FFmpeg
Stream #0.0[0x100]: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p, 640x480, 30 fps, 30 tbr, 90k tbn, 60 tbc
Stream #0.1[0x101]: Audio: aac ([6][0][0][0] / 0x0006), 96000 Hz, 4.0, s16, 9 kb/s
I think i doubt that MEPG2 TS will allow PCM Audio. It can take up MPI, MP2 or AAC. AAC is being taken up more as a default choice rather than identificaiton.
Also, unlike Video, Audio headers are not very descriminative. i.e. doesn't have start codes and stuff, so other than PES header, usually there is no way to find out what type of Audio it is.
Encode audio if possible.
Try Gspot application to cross check.
Looks like MPEG-TS supports AES3-formatted PCM audio as private data, as specified by SMPTE 302M.
There is currently a s302m encoder/decoder in ffmpeg that will allow you to easily accomplish your goal.
some time ago I played with it too. And what I found out is that:
- Blu-ray only support 48000 Sample Rate
- I always use BIG ENDIAN not LITTLE ENDIAN.
I think ffmpeg will use Blu-ray settings for mpeg2_ts.
Im trying read and store samples from an audio microphone in linux using C/C++. Using PCM ioctls i setup the device to have a certain sampling rate say 10Khz using the SOUND_PCM_WRITE_RATE ioctl etc. The device gets setup correctly and im able to read back from the device after setup using the "read".
int got = read(itsFd, b.getDataPtr(), b.sizeBytes());
The problem i have is that after setting the appropriate sampling rate i have a thread that continuously reads from /dev/dsp1 and stores these samples, but the number of samples that i get for 1 second of recording are way off the sampling rate and always orders of magnitude more than the set sampling rate. Any ideas where to begin on figuring out what might be the problem?
EDIT:
Partial source code:
/////////main loop
while(goforever) {
// grab a buffer:
AudioBuffer<uint16> buffer;
agb->grab(buffer);
pthread_mutex_lock(&qmutex_data);
rec.push(buffer);
pthread_mutex_unlock(&qmutex_data);
if(tim.getSecs()>=5)
goforever =false;
}
////////////grab function:
template <class T>
void AudioGrabber::grab(AudioBuffer<T>& buf) const
{
AudioBuffer<T> b(itsBufsamples.getVal(),
itsStereo.getVal() ? 2U : 1U,
float(itsFreq.getVal()),
NO_INIT);
int got = read(itsFd, b.getDataPtr(), b.sizeBytes());
if (got != int(b.sizeBytes()))
PLERROR("Error reading from device: got %d of %u requested bytes",
got, b.sizeBytes());
buf = b;
}
Just because you ask for a 10kHz sampling rate, it doesn't mean that your hardware supports it. Many sound cards only support one or two sampling rates - mine for example only supports these:
$ grep -rH rates /proc/asound/ | cut -d : -f 2- | sort -u
rates [0x160]: 44100 48000 96000
rates [0x560]: 44100 48000 96000 192000
rates [0x5e0]: 44100 48000 88200 96000 192000
Therefore, you have to check the return value of the SOUND_PCM_WRITE_RATE ioctl() to verify that you got the rate that you wanted, as mentioned here:
SOUND_PCM_WRITE_RATE
Sets the sampling rate in samples per second. Remember that all sound
cards have a limit on the range; the
driver will round the rate to the
nearest speed supported by the
hardware, returning the actual
(rounded) rate in the argument.