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