3 * Copyright (C) 2008-2019 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "audiopulse.h"
23 #include "adeviceprefs.h"
28 #include "playbackconfig.h"
29 #include "recordconfig.h"
31 #include <pulse/pulseaudio.h>
32 #include <pulse/simple.h>
34 AudioPulse::AudioPulse(AudioDevice *device)
35 : AudioLowLevel(device)
40 timer_lock = new Mutex("AudioPulse::timer_lock");
43 period_usecs = 1000000;
44 frag_usecs = period_usecs / 32;
49 AudioPulse::~AudioPulse()
51 delete (pa_sample_spec *)wr_spec;
52 delete (pa_sample_spec *)rd_spec;
58 int AudioPulse::open_input()
60 pa_sample_spec *ss = new pa_sample_spec();
63 ss->format = PA_SAMPLE_S16LE;
64 ss->rate = device->in_samplerate;
65 ss->channels = device->get_ichannels();
70 int AudioPulse::init_input()
72 pa_sample_spec *ss = (pa_sample_spec *)rd_spec;
75 if( device->in_config->pulse_in_server[0] )
76 server = device->in_config->pulse_in_server;
77 dsp_in = pa_simple_new(server, PROGRAM_NAME, PA_STREAM_RECORD,
78 0, "recording", ss, 0, 0, &error);
80 printf("AudioPulse::open_input %d: failed server=%s %s\n", __LINE__,
81 server, pa_strerror(error));
89 int AudioPulse::open_output()
91 pa_sample_spec *ss = new pa_sample_spec();
93 ss->format = PA_SAMPLE_S16LE;
94 ss->rate = device->out_samplerate;
95 ss->channels = device->get_ochannels();
96 device->out_bits = 16;
100 int AudioPulse::init_output()
102 pa_sample_spec *ss = (pa_sample_spec *)wr_spec;
104 char *server = device->out_config->pulse_out_server[0] ?
105 device->out_config->pulse_out_server : 0;
106 dsp_out = pa_simple_new(server, PROGRAM_NAME, PA_STREAM_PLAYBACK,
107 NULL, "playback", ss, 0, 0, &error);
109 printf("AudioPulse::open_output %d: failed server=%s %s\n",
110 __LINE__, server, pa_strerror(error));
114 device->device_buffer = 0;
120 int AudioPulse::close_all()
124 pa_simple_flush((pa_simple*)dsp_out, &error);
125 pa_simple_free((pa_simple*)dsp_out);
130 pa_simple_free((pa_simple*)dsp_in);
133 delete (pa_sample_spec *)wr_spec; wr_spec = 0;
134 delete (pa_sample_spec *)rd_spec; rd_spec = 0;
140 int64_t AudioPulse::device_position()
142 timer_lock->lock("AudioPulse::device_position");
143 int64_t samples = timer->get_scaled_difference(device->out_samplerate);
144 int64_t result = timer_position + samples;
145 timer_lock->unlock();
149 int AudioPulse::write_buffer(char *buffer, int size)
151 if( !dsp_out && init_output() )
154 timer_lock->lock("AudioPulse::write_buffer");
155 int64_t usecs = pa_simple_get_latency((pa_simple*)dsp_out, &error);
156 int64_t delay = device->out_samplerate * usecs / 1000000;
157 timer_position = buffer_position - delay;
159 timer_lock->unlock();
161 AudioThread *audio_out = device->audio_out;
162 int sample_size = (device->out_bits / 8) * device->get_ochannels();
163 int samples = device->out_samplerate * frag_usecs / 1000000;
164 int64_t frag_bytes = samples * sample_size;
166 buffer_position += size / sample_size;
168 while( !ret && size > 0 && !device->playback_interrupted ) {
169 audio_out->Thread::enable_cancel();
170 usecs = pa_simple_get_latency((pa_simple*)dsp_out, &error);
171 if( usecs < period_usecs ) {
173 if( len > frag_bytes ) len = frag_bytes;
174 if( pa_simple_write((pa_simple*)dsp_out, buffer, len, &error) < 0 )
176 buffer += len; size -= len;
180 audio_out->Thread::disable_cancel();
183 printf("AudioPulse::write_buffer %d: %s\n",
184 __LINE__, pa_strerror(error));
188 int AudioPulse::read_buffer(char *buffer, int size)
190 if( !dsp_in && init_input() )
194 int result = pa_simple_read((pa_simple*)dsp_in, buffer, size, &error);
196 printf("AudioPulse::read_buffer %d: %s\n",
197 __LINE__, pa_strerror(error));
201 //printf("AudioPulse::read_buffer %d %d\n", __LINE__, size);
206 int AudioPulse::output_wait()
209 pa_usec_t latency = pa_simple_get_latency((pa_simple*)dsp_out, &error);
210 int64_t udelay = latency;
211 while( udelay > 0 && !device->playback_interrupted ) {
212 int64_t usecs = udelay;
213 if( usecs > 100000 ) usecs = 100000;
217 if( device->playback_interrupted &&
218 !device->out_config->interrupt_workaround )
219 pa_simple_flush((pa_simple*)dsp_out, &error);
223 int AudioPulse::flush_device()
228 pa_simple_drain((pa_simple*)dsp_out, &error);
233 int AudioPulse::interrupt_playback()
240 int result = pa_simple_flush((pa_simple*)dsp_out, &error);
242 printf("AudioPulse::interrupt_playback %d: %s\n",