1 /*
2 Copyright (C) 2008 Remon Sijrier
3
4 This file is part of Traverso
5
6 Traverso is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 */
21
22 #include "PulseAudioDriver.h"
23
24 #include <pulse/error.h>
25
26 #include "AudioDevice.h"
27 #include "AudioChannel.h"
28
29 // Always put me below _all_ includes, this is needed
30 // in case we run with memory leak detection enabled!
31 #include "Debugger.h"
32
PulseAudioDriver(AudioDevice * dev,int rate,nframes_t bufferSize)33 PulseAudioDriver::PulseAudioDriver( AudioDevice * dev , int rate, nframes_t bufferSize)
34 : Driver(dev, rate, bufferSize)
35 {
36 read = MakeDelegate(this, &PulseAudioDriver::_read);
37 write = MakeDelegate(this, &PulseAudioDriver::_write);
38 run_cycle = RunCycleCallback(this, &PulseAudioDriver::_run_cycle);
39
40 mainloop = NULL;
41 context = NULL;
42 stream = NULL;
43 mainloop_api = NULL;
44 volume = PA_VOLUME_NORM;
45 channel_map_set = 0;
46 }
47
~PulseAudioDriver()48 PulseAudioDriver::~PulseAudioDriver( )
49 {
50 PENTER;
51 if (stream)
52 pa_stream_unref(stream);
53
54 if (context)
55 pa_context_unref(context);
56
57 if (mainloop) {
58 pa_signal_done();
59 pa_mainloop_free(mainloop);
60 }
61 }
62
_read(nframes_t nframes)63 int PulseAudioDriver::_read( nframes_t nframes )
64 {
65 return 1;
66 }
67
_write(nframes_t nframes)68 int PulseAudioDriver::_write( nframes_t nframes )
69 {
70 return 1;
71 }
72
setup(bool capture,bool playback,const QString &)73 int PulseAudioDriver::setup(bool capture, bool playback, const QString& )
74 {
75 PENTER;
76
77 sample_spec.rate = frame_rate;
78 sample_spec.channels = 2;
79 sample_spec.format = PA_SAMPLE_FLOAT32NE;
80
81 assert(pa_sample_spec_valid(&sample_spec));
82
83 if (channel_map_set && channel_map.channels != sample_spec.channels) {
84 fprintf(stderr, "Channel map doesn't match file.\n");
85 return -1;
86 }
87
88 /* Set up a new main loop */
89 if (!(mainloop = pa_mainloop_new())) {
90 fprintf(stderr, "pa_mainloop_new() failed.\n");
91 return -1;
92 }
93
94 mainloop_api = pa_mainloop_get_api(mainloop);
95
96 int r = pa_signal_init(mainloop_api);
97 assert(r == 0);
98
99 /* Create a new connection context */
100 if (!(context = pa_context_new(mainloop_api, "Traverso"))) {
101 fprintf(stderr, "pa_context_new() failed.\n");
102 return -1;
103 }
104
105 pa_context_set_state_callback(context, context_state_callback, this);
106
107 /* Connect the context */
108 pa_context_connect(context, "", (pa_context_flags_t)0, NULL);
109
110 int ret;
111 /* Run the main loop */
112 // if (pa_mainloop_run(mainloop, &ret) < 0) {
113 // fprintf(stderr, "pa_mainloop_run() failed.\n");
114 // return -1;
115 // }
116
117
118 AudioChannel* audiochannel;
119 int port_flags;
120 char buf[32];
121
122 // TODO use the found maxchannel count for the playback stream, instead of assuming 2 !!
123 for (int chn = 0; chn < 2; chn++) {
124
125 snprintf (buf, sizeof(buf) - 1, "playback_%d", chn+1);
126
127 audiochannel = device->register_playback_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn);
128 audiochannel->set_latency( frames_per_cycle + capture_frame_latency );
129 playbackChannels.append(audiochannel);
130 }
131
132 // TODO use the found maxchannel count for the capture stream, instead of assuming 0 !!
133 for (int chn = 0; chn < 2; chn++) {
134
135 snprintf (buf, sizeof(buf) - 1, "capture_%d", chn+1);
136
137 audiochannel = device->register_capture_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn);
138 audiochannel->set_latency( frames_per_cycle + capture_frame_latency );
139 captureChannels.append(audiochannel);
140 }
141
142 return 1;
143 }
144
attach()145 int PulseAudioDriver::attach( )
146 {
147 PENTER;
148 return 1;
149 }
150
start()151 int PulseAudioDriver::start( )
152 {
153 PENTER;
154 return 1;
155 }
156
stop()157 int PulseAudioDriver::stop( )
158 {
159 PENTER;
160 return 1;
161 }
162
process_callback(nframes_t nframes)163 int PulseAudioDriver::process_callback (nframes_t nframes)
164 {
165 device->run_cycle( nframes, 0.0);
166 return 0;
167 }
168
get_device_name()169 QString PulseAudioDriver::get_device_name()
170 {
171 return "Pulse";
172 }
173
get_device_longname()174 QString PulseAudioDriver::get_device_longname()
175 {
176 return "Pulse";
177 }
178
_run_cycle()179 int PulseAudioDriver::_run_cycle()
180 {
181 return device->run_cycle(frames_per_cycle, 0);
182 }
183
context_state_callback(pa_context * c,void * userdata)184 void PulseAudioDriver::context_state_callback(pa_context * c, void * userdata)
185 {
186 }
187
stream_state_callback(pa_stream * s,void * userdata)188 void PulseAudioDriver::stream_state_callback(pa_stream * s, void * userdata)
189 {
190 }
191
stream_write_callback(pa_stream * s,size_t length,void * userdata)192 void PulseAudioDriver::stream_write_callback(pa_stream * s, size_t length, void * userdata)
193 {
194 }
195
196