1/* ---------------------------------------------------------------------------
2** This software is in the public domain, furnished "as is", without technical
3** support, and with no warranty, express or implied, as to its usefulness for
4** any purpose.
5**
6** ALSACapture.cpp
7**
8** V4L2 RTSP streamer
9**
10** ALSA capture overide of V4l2Capture
11**
12** -------------------------------------------------------------------------*/
13
14#ifdef HAVE_ALSA
15
16#include "ALSACapture.h"
17
18
19ALSACapture* ALSACapture::createNew(const ALSACaptureParameters & params)
20{
21 ALSACapture* capture = new ALSACapture(params);
22 if (capture)
23 {
24 if (capture->getFd() == -1)
25 {
26 delete capture;
27 capture = NULL;
28 }
29 }
30 return capture;
31}
32
33ALSACapture::~ALSACapture()
34{
35 this->close();
36}
37
38void ALSACapture::close()
39{
40 if (m_pcm != NULL)
41 {
42 snd_pcm_close (m_pcm);
43 m_pcm = NULL;
44 }
45}
46
47ALSACapture::ALSACapture(const ALSACaptureParameters & params) : m_pcm(NULL), m_bufferSize(0), m_periodSize(0), m_params(params)
48{
49 LOG(NOTICE) << "Open ALSA device: \"" << params.m_devName << "\"";
50
51 snd_pcm_hw_params_t *hw_params = NULL;
52 int err = 0;
53
54 // open PCM device
55 if ((err = snd_pcm_open (&m_pcm, m_params.m_devName.c_str(), SND_PCM_STREAM_CAPTURE, 0)) < 0) {
56 LOG(ERROR) << "cannot open audio device: " << m_params.m_devName << " error:" << snd_strerror (err);
57 }
58
59 // configure hw_params
60 else if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
61 LOG(ERROR) << "cannot allocate hardware parameter structure device: " << m_params.m_devName << " error:" << snd_strerror (err);
62 this->close();
63 }
64 else if ((err = snd_pcm_hw_params_any (m_pcm, hw_params)) < 0) {
65 LOG(ERROR) << "cannot initialize hardware parameter structure device: " << m_params.m_devName << " error:" << snd_strerror (err);
66 this->close();
67 }
68 else if ((err = snd_pcm_hw_params_set_access (m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
69 LOG(ERROR) << "cannot set access type device: " << m_params.m_devName << " error:" << snd_strerror (err);
70 this->close();
71 }
72 else if (this->configureFormat(hw_params) < 0) {
73 this->close();
74 }
75 else if ((err = snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &m_params.m_sampleRate, 0)) < 0) {
76 LOG(ERROR) << "cannot set sample rate device: " << m_params.m_devName << " error:" << snd_strerror (err);
77 this->close();
78 }
79 else if ((err = snd_pcm_hw_params_set_channels (m_pcm, hw_params, m_params.m_channels)) < 0) {
80 LOG(ERROR) << "cannot set channel count device: " << m_params.m_devName << " error:" << snd_strerror (err);
81 this->close();
82 }
83 else if ((err = snd_pcm_hw_params (m_pcm, hw_params)) < 0) {
84 LOG(ERROR) << "cannot set parameters device: " << m_params.m_devName << " error:" << snd_strerror (err);
85 this->close();
86 }
87
88 // get buffer size
89 else if ((err = snd_pcm_get_params(m_pcm, &m_bufferSize, &m_periodSize)) < 0) {
90 LOG(ERROR) << "cannot get parameters device: " << m_params.m_devName << " error:" << snd_strerror (err);
91 this->close();
92 }
93
94 // start capture
95 else if ((err = snd_pcm_prepare (m_pcm)) < 0) {
96 LOG(ERROR) << "cannot prepare audio interface for use device: " << m_params.m_devName << " error:" << snd_strerror (err);
97 this->close();
98 }
99 else if ((err = snd_pcm_start (m_pcm)) < 0) {
100 LOG(ERROR) << "cannot start audio interface for use device: " << m_params.m_devName << " error:" << snd_strerror (err);
101 this->close();
102 }
103
104 LOG(NOTICE) << "ALSA device: \"" << m_params.m_devName << "\" buffer_size:" << m_bufferSize << " period_size:" << m_periodSize << " rate:" << m_params.m_sampleRate;
105}
106
107int ALSACapture::configureFormat(snd_pcm_hw_params_t *hw_params) {
108
109 // try to set format, widht, height
110 std::list<snd_pcm_format_t>::iterator it;
111 for (it = m_params.m_formatList.begin(); it != m_params.m_formatList.end(); ++it) {
112 snd_pcm_format_t format = *it;
113 int err = snd_pcm_hw_params_set_format (m_pcm, hw_params, format);
114 if (err < 0) {
115 LOG(NOTICE) << "cannot set sample format device: " << m_params.m_devName << " to:" << format << " error:" << snd_strerror (err);
116 } else {
117 LOG(NOTICE) << "set sample format device: " << m_params.m_devName << " to:" << format << " ok";
118 m_fmt = format;
119 return 0;
120 }
121 }
122 return -1;
123}
124
125size_t ALSACapture::read(char* buffer, size_t bufferSize)
126{
127 size_t size = 0;
128 int fmt_phys_width_bytes = 0;
129 if (m_pcm != 0)
130 {
131 int fmt_phys_width_bits = snd_pcm_format_physical_width(m_fmt);
132 fmt_phys_width_bytes = fmt_phys_width_bits / 8;
133
134 snd_pcm_sframes_t ret = snd_pcm_readi (m_pcm, buffer, m_periodSize*fmt_phys_width_bytes);
135 LOG(DEBUG) << "ALSA buffer in_size:" << m_periodSize*fmt_phys_width_bytes << " read_size:" << ret;
136 if (ret > 0) {
137 size = ret;
138
139 // swap if capture in not in network order
140 if (!snd_pcm_format_big_endian(m_fmt)) {
141 for(unsigned int i = 0; i < size; i++){
142 char * ptr = &buffer[i * fmt_phys_width_bytes * m_params.m_channels];
143
144 for(unsigned int j = 0; j < m_params.m_channels; j++){
145 ptr += j * fmt_phys_width_bytes;
146 for (int k = 0; k < fmt_phys_width_bytes/2; k++) {
147 char byte = ptr[k];
148 ptr[k] = ptr[fmt_phys_width_bytes - 1 - k];
149 ptr[fmt_phys_width_bytes - 1 - k] = byte;
150 }
151 }
152 }
153 }
154 }
155 }
156 return size * m_params.m_channels * fmt_phys_width_bytes;
157}
158
159int ALSACapture::getFd()
160{
161 unsigned int nbfs = 1;
162 struct pollfd pfds[nbfs];
163 pfds[0].fd = -1;
164
165 if (m_pcm != 0)
166 {
167 int count = snd_pcm_poll_descriptors_count (m_pcm);
168 int err = snd_pcm_poll_descriptors(m_pcm, pfds, count);
169 if (err < 0) {
170 fprintf (stderr, "cannot snd_pcm_poll_descriptors (%s)\n", snd_strerror (err));
171 }
172 }
173 return pfds[0].fd;
174}
175
176#endif
177
178
179