Move AudioBackend related debug bits into libardour
[ardour.git] / libs / backends / portaudio / portaudio_io.cc
1 /*
2  * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
4  *
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.
9  *
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.
14  *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <glibmm.h>
25
26 #include "portaudio_io.h"
27
28 #ifdef WITH_ASIO
29 #include "pa_asio.h"
30 #endif
31
32 #include "pbd/compose.h"
33
34 #include "ardour/audio_backend.h"
35
36 #include "debug.h"
37
38 #define INTERLEAVED_INPUT
39 #define INTERLEAVED_OUTPUT
40
41 using namespace PBD;
42 using namespace ARDOUR;
43
44 PortAudioIO::PortAudioIO ()
45         : _state (-1)
46         , _initialized (false)
47         , _capture_channels (0)
48         , _playback_channels (0)
49         , _stream (0)
50         , _input_buffer (0)
51         , _output_buffer (0)
52         , _cur_sample_rate (0)
53         , _cur_input_latency (0)
54         , _cur_output_latency (0)
55         , _host_api_index(-1)
56 {
57 }
58
59 PortAudioIO::~PortAudioIO ()
60 {
61         if (_state == 0) {
62                 pcm_stop();
63         }
64         if (_initialized) {
65                 Pa_Terminate();
66         }
67
68         clear_device_lists ();
69
70         free (_input_buffer); _input_buffer = NULL;
71         free (_output_buffer); _output_buffer = NULL;
72 }
73
74 std::string
75 PortAudioIO::control_app_name (int device_id) const
76 {
77 #ifdef WITH_ASIO
78         if (get_current_host_api_type() == paASIO) {
79                 // is this used for anything, or just acts as a boolean?
80                 return "PortaudioASIO";
81         }
82 #endif
83
84         return std::string();
85 }
86
87 void
88 PortAudioIO::launch_control_app (int device_id)
89 {
90 #ifdef WITH_ASIO
91         PaError err = PaAsio_ShowControlPanel (device_id, NULL);
92
93         if (err != paNoError) {
94                 // error << ?
95                 DEBUG_AUDIO (string_compose (
96                     "Unable to show control panel for device with index %1\n", device_id));
97         }
98 #endif
99 }
100
101 int
102 PortAudioIO::available_sample_rates(int device_id, std::vector<float>& sampleRates)
103 {
104         static const float ardourRates[] = { 8000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0};
105
106         if (!initialize_pa()) return -1;
107
108         // TODO use  separate int device_input, int device_output ?!
109         if (device_id == DeviceDefault) {
110                 device_id = get_default_input_device ();
111         }
112
113         DEBUG_AUDIO (
114             string_compose ("Querying Samplerates for device %1\n", device_id));
115
116         sampleRates.clear();
117         const PaDeviceInfo* nfo = Pa_GetDeviceInfo(device_id);
118
119         if (nfo) {
120                 PaStreamParameters inputParam;
121                 PaStreamParameters outputParam;
122
123                 inputParam.device = device_id;
124                 inputParam.channelCount = nfo->maxInputChannels;
125                 inputParam.sampleFormat = paFloat32;
126                 inputParam.suggestedLatency = 0;
127                 inputParam.hostApiSpecificStreamInfo = 0;
128
129                 outputParam.device = device_id;
130                 outputParam.channelCount = nfo->maxOutputChannels;
131                 outputParam.sampleFormat = paFloat32;
132                 outputParam.suggestedLatency = 0;
133                 outputParam.hostApiSpecificStreamInfo = 0;
134
135                 for (uint32_t i = 0; i < sizeof(ardourRates)/sizeof(float); ++i) {
136                         if (paFormatIsSupported == Pa_IsFormatSupported(
137                                                 nfo->maxInputChannels > 0 ? &inputParam : NULL,
138                                                 nfo->maxOutputChannels > 0 ? &outputParam : NULL,
139                                                 ardourRates[i])) {
140                                 sampleRates.push_back (ardourRates[i]);
141                         }
142                 }
143         }
144
145         if (sampleRates.empty()) {
146                 // fill in something..
147                 sampleRates.push_back (44100.0);
148                 sampleRates.push_back (48000.0);
149         }
150
151         return 0;
152 }
153
154 #ifdef WITH_ASIO
155 bool
156 PortAudioIO::get_asio_buffer_properties (int device_id,
157                                          long& min_size_frames,
158                                          long& max_size_frames,
159                                          long& preferred_size_frames,
160                                          long& granularity)
161 {
162         // we shouldn't really need all these checks but it shouldn't hurt
163         const PaDeviceInfo* device_info = Pa_GetDeviceInfo(device_id);
164
165         if (!device_info) {
166                 DEBUG_AUDIO (string_compose (
167                     "Unable to get device info from device index %1\n", device_id));
168                 return false;
169         }
170
171         if (get_current_host_api_type() != paASIO) {
172                 DEBUG_AUDIO (string_compose (
173                     "ERROR device_id %1 is not an ASIO device\n", device_id));
174                 return false;
175         }
176
177         PaError err = PaAsio_GetAvailableBufferSizes (device_id,
178                                                       &min_size_frames,
179                                                       &max_size_frames,
180                                                       &preferred_size_frames,
181                                                       &granularity);
182
183         if (err != paNoError) {
184                 DEBUG_AUDIO (string_compose (
185                     "Unable to determine available buffer sizes for device %1\n", device_id));
186                 return false;
187         }
188         return true;
189 }
190
191 bool
192 PortAudioIO::get_asio_buffer_sizes (int device_id, std::vector<uint32_t>& buffer_sizes)
193 {
194         long min_size_frames = 0;
195         long max_size_frames = 0;
196         long preferred_size_frames = 0;
197         long granularity = 0;
198
199         if (!get_asio_buffer_properties (device_id,
200                                          min_size_frames,
201                                          max_size_frames,
202                                          preferred_size_frames,
203                                          granularity)) {
204                 DEBUG_AUDIO (string_compose (
205                     "Unable to get device buffer properties from device index %1\n", device_id));
206                 return false;
207         }
208
209         DEBUG_AUDIO (string_compose ("ASIO buffer properties for device %1, "
210                                      "min_size_frames: %2, max_size_frames: %3, "
211                                      "preferred_size_frames: %4, granularity: %5\n",
212                                      device_id,
213                                      min_size_frames,
214                                      max_size_frames,
215                                      preferred_size_frames,
216                                      granularity));
217
218 #ifdef USE_ASIO_MIN_MAX_BUFFER_SIZES
219         if (min_size_frames >= max_size_frames) {
220                 buffer_sizes.push_back (preferred_size_frames);
221                 return true;
222         }
223
224         long buffer_size = min_size_frames;
225         while (buffer_size <= max_size_frames) {
226                 buffer_sizes.push_back (buffer_size);
227
228                 if (granularity <= 0) {
229                         // buffer sizes are power of 2
230                         buffer_size = buffer_size * 2;
231                 } else {
232                         buffer_size += granularity;
233                 }
234         }
235 #else
236         buffer_sizes.push_back (preferred_size_frames);
237 #endif
238         return true;
239 }
240 #endif
241
242 bool
243 PortAudioIO::get_default_buffer_sizes (int device_id, std::vector<uint32_t>& buffer_sizes)
244 {
245         static const uint32_t ardourSizes[] = { 64, 128, 256, 512, 1024, 2048, 4096 };
246         for(uint32_t i = 0; i < sizeof(ardourSizes)/sizeof(uint32_t); ++i) {
247                 buffer_sizes.push_back (ardourSizes[i]);
248         }
249         return true;
250 }
251
252 int
253 PortAudioIO::available_buffer_sizes(int device_id, std::vector<uint32_t>& buffer_sizes)
254 {
255 #ifdef WITH_ASIO
256         if (get_current_host_api_type() == paASIO) {
257                 if (get_asio_buffer_sizes (device_id, buffer_sizes)) {
258                         return 0;
259                 }
260         }
261 #endif
262
263         get_default_buffer_sizes (device_id, buffer_sizes);
264
265         return 0;
266 }
267
268 void
269 PortAudioIO::input_device_list(std::map<int, std::string> &devices) const
270 {
271         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin ();
272              i != _input_devices.end ();
273              ++i) {
274                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
275         }
276 }
277
278 void
279 PortAudioIO::output_device_list(std::map<int, std::string> &devices) const
280 {
281         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin ();
282              i != _output_devices.end ();
283              ++i) {
284                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
285         }
286 }
287
288 bool
289 PortAudioIO::initialize_pa ()
290 {
291         PaError err = paNoError;
292
293         if (!_initialized) {
294                 err = Pa_Initialize();
295                 if (err != paNoError) {
296                         return false;
297                 }
298                 _initialized = true;
299                 _host_api_index = Pa_GetDefaultHostApi ();
300                 _host_api_name = get_host_api_name_from_index (_host_api_index);
301         }
302
303         return true;
304 }
305
306 void
307 PortAudioIO::host_api_list (std::vector<std::string>& api_list)
308 {
309         if (!initialize_pa()) return;
310
311         PaHostApiIndex count = Pa_GetHostApiCount();
312
313         if (count < 0) return;
314
315         for (int i = 0; i < count; ++i) {
316                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
317                 if (info->name != NULL) { // possible?
318                         api_list.push_back (info->name);
319                 }
320         }
321 }
322
323
324 PaHostApiTypeId
325 PortAudioIO::get_current_host_api_type () const
326 {
327         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
328
329         if (info == NULL) {
330                 DEBUG_AUDIO(string_compose(
331                     "Unable to determine Host API type from index %1\n", _host_api_index));
332                 return (PaHostApiTypeId)0;
333         }
334
335         return info->type;
336 }
337
338 std::string
339 PortAudioIO::get_host_api_name_from_index (PaHostApiIndex index)
340 {
341         std::vector<std::string> api_list;
342         host_api_list(api_list);
343         return api_list[index];
344 }
345
346 bool
347 PortAudioIO::set_host_api (const std::string& host_api_name)
348 {
349         PaHostApiIndex new_index = get_host_api_index_from_name (host_api_name);
350
351         if (new_index < 0) {
352                 DEBUG_AUDIO ("Portaudio: Error setting host API\n");
353                 return false;
354         }
355         _host_api_index = new_index;
356         _host_api_name = host_api_name;
357         return true;
358 }
359
360 PaHostApiIndex
361 PortAudioIO::get_host_api_index_from_name (const std::string& name)
362 {
363         if (!initialize_pa()) return -1;
364
365         PaHostApiIndex count = Pa_GetHostApiCount();
366
367         if (count < 0) {
368                 DEBUG_AUDIO ("Host API count < 0\n");
369                 return -1;
370         }
371
372         for (int i = 0; i < count; ++i) {
373                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
374                 if (info != NULL && info->name != NULL) { // possible?
375                         if (name == info->name) {
376                                 return i;
377                         }
378                 }
379         }
380         DEBUG_AUDIO (string_compose ("Unable to get host API from name: %1\n", name));
381
382         return -1;
383 }
384
385 PaDeviceIndex
386 PortAudioIO::get_default_input_device ()
387 {
388         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
389         if (info == NULL) return -1;
390         return info->defaultInputDevice;
391 }
392
393 PaDeviceIndex
394 PortAudioIO::get_default_output_device ()
395 {
396         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
397         if (info == NULL) return -1;
398         return info->defaultOutputDevice;
399 }
400
401 void
402 PortAudioIO::clear_device_lists ()
403 {
404         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin (); i != _input_devices.end(); ++i) {
405                 delete i->second;
406         }
407         _input_devices.clear();
408
409         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin (); i != _output_devices.end(); ++i) {
410                 delete i->second;
411         }
412         _output_devices.clear();
413 }
414
415 void
416 PortAudioIO::add_none_devices ()
417 {
418         _input_devices.insert(std::pair<int, paDevice*>(
419             DeviceNone, new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceNone), 0, 0)));
420         _output_devices.insert(std::pair<int, paDevice*>(
421             DeviceNone, new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceNone), 0, 0)));
422 }
423
424 void
425 PortAudioIO::add_default_devices ()
426 {
427         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
428         if (info == NULL) return;
429
430         const PaDeviceInfo* nfo_i = Pa_GetDeviceInfo(get_default_input_device());
431         const PaDeviceInfo* nfo_o = Pa_GetDeviceInfo(get_default_output_device());
432         if (nfo_i && nfo_o) {
433                 _input_devices.insert (std::pair<int, paDevice*> (DeviceDefault,
434                                         new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault),
435                                                 nfo_i->maxInputChannels,
436                                                 nfo_o->maxOutputChannels
437                                                 )));
438                 _output_devices.insert (std::pair<int, paDevice*> (DeviceDefault,
439                                         new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault),
440                                                 nfo_i->maxInputChannels,
441                                                 nfo_o->maxOutputChannels
442                                                 )));
443         }
444 }
445
446 void
447 PortAudioIO::add_devices ()
448 {
449         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
450         if (info == NULL) return;
451
452         int n_devices = Pa_GetDeviceCount();
453
454         DEBUG_AUDIO (string_compose ("PortAudio found %1 devices\n", n_devices));
455
456         for (int i = 0 ; i < n_devices; ++i) {
457                 const PaDeviceInfo* nfo = Pa_GetDeviceInfo(i);
458
459                 if (!nfo) continue;
460                 if (nfo->hostApi != _host_api_index) continue;
461
462                 DEBUG_AUDIO (string_compose (" (%1) '%2' '%3' in: %4 (lat: %5 .. %6) out: %7 "
463                                              "(lat: %8 .. %9) sr:%10\n",
464                                              i,
465                                              info->name,
466                                              nfo->name,
467                                              nfo->maxInputChannels,
468                                              nfo->defaultLowInputLatency * 1e3,
469                                              nfo->defaultHighInputLatency * 1e3,
470                                              nfo->maxOutputChannels,
471                                              nfo->defaultLowOutputLatency * 1e3,
472                                              nfo->defaultHighOutputLatency * 1e3,
473                                              nfo->defaultSampleRate));
474
475                 if ( nfo->maxInputChannels == 0 && nfo->maxOutputChannels == 0) {
476                         continue;
477                 }
478
479                 if (nfo->maxInputChannels > 0) {
480                         _input_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
481                                                         nfo->name,
482                                                         nfo->maxInputChannels,
483                                                         nfo->maxOutputChannels
484                                                         )));
485                 }
486                 if (nfo->maxOutputChannels > 0) {
487                         _output_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
488                                                         nfo->name,
489                                                         nfo->maxInputChannels,
490                                                         nfo->maxOutputChannels
491                                                         )));
492                 }
493         }
494 }
495
496 void
497 PortAudioIO::discover()
498 {
499         DEBUG_AUDIO ("PortAudio: discover\n");
500         if (!initialize_pa()) return;
501
502         clear_device_lists ();
503         add_none_devices ();
504         add_devices ();
505 }
506
507 void
508 PortAudioIO::pcm_stop ()
509 {
510         if (_stream) {
511                 Pa_CloseStream (_stream);
512         }
513         _stream = NULL;
514
515         _capture_channels = 0;
516         _playback_channels = 0;
517         _cur_sample_rate = 0;
518         _cur_input_latency = 0;
519         _cur_output_latency = 0;
520
521         free (_input_buffer); _input_buffer = NULL;
522         free (_output_buffer); _output_buffer = NULL;
523         _state = -1;
524 }
525
526 int
527 PortAudioIO::pcm_start()
528 {
529         PaError err = Pa_StartStream (_stream);
530
531         if (err != paNoError) {
532                 _state = -1;
533                 return -1;
534         }
535         return 0;
536 }
537
538 #ifdef __APPLE__
539 static uint32_t lower_power_of_two (uint32_t v) {
540         v--;
541         v |= v >> 1;
542         v |= v >> 2;
543         v |= v >> 4;
544         v |= v >> 8;
545         v |= v >> 16;
546         v++;
547         return v >> 1;
548 }
549 #endif
550
551 int
552 PortAudioIO::pcm_setup (
553                 int device_input, int device_output,
554                 double sample_rate, uint32_t samples_per_period)
555 {
556         _state = -2;
557
558         PaError err = paNoError;
559         const PaDeviceInfo *nfo_in = NULL;
560         const PaDeviceInfo *nfo_out = NULL;
561         const PaStreamInfo *nfo_s = NULL;
562                 
563         if (!initialize_pa()) {
564                 DEBUG_AUDIO ("PortAudio Initialization Failed\n");
565                 goto error;
566         }
567
568         if (device_input == DeviceDefault) {
569                 device_input = get_default_input_device ();
570         }
571         if (device_output == DeviceDefault) {
572                 device_output = get_default_output_device ();
573         }
574
575         _capture_channels = 0;
576         _playback_channels = 0;
577         _cur_sample_rate = 0;
578         _cur_input_latency = 0;
579         _cur_output_latency = 0;
580
581         DEBUG_AUDIO (string_compose (
582             "PortAudio Device IDs: i:%1 o:%2\n", device_input, device_output));
583
584         if (device_input == DeviceNone && device_output == DeviceNone) {
585                 // just send the error msg for now rather than return it
586                 error << AudioBackend::get_error_string(AudioBackend::DeviceConfigurationNotSupportedError)
587                       << endmsg;
588                 return -1;
589         }
590
591         if (device_input != DeviceNone) {
592                 nfo_in = Pa_GetDeviceInfo(device_input);
593         }
594
595         if (device_output != DeviceNone) {
596                 nfo_out = Pa_GetDeviceInfo(device_output);
597         }
598
599         if (!nfo_in && ! nfo_out) {
600                 DEBUG_AUDIO ("PortAudio Cannot Query Device Info\n");
601                 goto error;
602         }
603
604         if (nfo_in) {
605                 _capture_channels = nfo_in->maxInputChannels;
606         }
607         if (nfo_out) {
608                 _playback_channels = nfo_out->maxOutputChannels;
609         }
610
611         if(_capture_channels == 0 && _playback_channels == 0) {
612                 DEBUG_AUDIO ("PortAudio no input or output channels.\n");
613                 goto error;
614         }
615
616 #ifdef __APPLE__
617         // pa_mac_core_blocking.c pa_stable_v19_20140130
618         // BUG: ringbuffer alloc requires power-of-two chn count.
619         if ((_capture_channels & (_capture_channels - 1)) != 0) {
620                 DEBUG_AUDIO (
621                     "Adjusted capture channels to power of two (portaudio rb bug)\n");
622                 _capture_channels = lower_power_of_two (_capture_channels);
623         }
624
625         if ((_playback_channels & (_playback_channels - 1)) != 0) {
626                 DEBUG_AUDIO (
627                     "Adjusted capture channels to power of two (portaudio rb bug)\n");
628                 _playback_channels = lower_power_of_two (_playback_channels);
629         }
630 #endif
631
632         DEBUG_AUDIO (string_compose ("PortAudio Channels: in:%1 out:%2\n",
633                                      _capture_channels,
634                                      _playback_channels));
635
636         PaStreamParameters inputParam;
637         PaStreamParameters outputParam;
638
639         if (nfo_in) {
640                 inputParam.device = device_input;
641                 inputParam.channelCount = _capture_channels;
642 #ifdef INTERLEAVED_INPUT
643                 inputParam.sampleFormat = paFloat32;
644 #else
645                 inputParam.sampleFormat = paFloat32 | paNonInterleaved;
646 #endif
647                 inputParam.suggestedLatency = nfo_in->defaultLowInputLatency;
648                 inputParam.hostApiSpecificStreamInfo = NULL;
649         }
650
651         if (nfo_out) {
652                 outputParam.device = device_output;
653                 outputParam.channelCount = _playback_channels;
654 #ifdef INTERLEAVED_OUTPUT
655                 outputParam.sampleFormat = paFloat32;
656 #else
657                 outputParam.sampleFormat = paFloat32 | paNonInterleaved;
658 #endif
659                 outputParam.suggestedLatency = nfo_out->defaultLowOutputLatency;
660                 outputParam.hostApiSpecificStreamInfo = NULL;
661         }
662
663         // XXX re-consider using callback API, testing needed.
664         err = Pa_OpenStream (
665                         &_stream,
666                         _capture_channels > 0 ? &inputParam: NULL,
667                         _playback_channels > 0 ? &outputParam: NULL,
668                         sample_rate,
669                         samples_per_period,
670                         paDitherOff,
671                         NULL, NULL);
672
673         if (err != paNoError) {
674                 DEBUG_AUDIO ("PortAudio failed to start stream.\n");
675                 goto error;
676         }
677
678         nfo_s = Pa_GetStreamInfo (_stream);
679         if (!nfo_s) {
680                 DEBUG_AUDIO ("PortAudio failed to query stream information.\n");
681                 pcm_stop();
682                 goto error;
683         }
684
685         _cur_sample_rate = nfo_s->sampleRate;
686         _cur_input_latency = nfo_s->inputLatency * _cur_sample_rate;
687         _cur_output_latency = nfo_s->outputLatency * _cur_sample_rate;
688
689         DEBUG_AUDIO (string_compose ("PA Sample Rate %1 SPS\n", _cur_sample_rate));
690
691         DEBUG_AUDIO (string_compose ("PA Input Latency %1ms, %2 spl\n",
692                                      1e3 * nfo_s->inputLatency,
693                                      _cur_input_latency));
694
695         DEBUG_AUDIO (string_compose ("PA Output Latency %1ms, %2 spl\n",
696                                      1e3 * nfo_s->outputLatency,
697                                      _cur_output_latency));
698
699         _state = 0;
700
701         if (_capture_channels > 0) {
702                 _input_buffer = (float*) malloc (samples_per_period * _capture_channels * sizeof(float));
703                 if (!_input_buffer) {
704                         DEBUG_AUDIO ("PortAudio failed to allocate input buffer.\n");
705                         pcm_stop();
706                         goto error;
707                 }
708         }
709
710         if (_playback_channels > 0) {
711                 _output_buffer = (float*) calloc (samples_per_period * _playback_channels, sizeof(float));
712                 if (!_output_buffer) {
713                         DEBUG_AUDIO ("PortAudio failed to allocate output buffer.\n");
714                         pcm_stop();
715                         goto error;
716                 }
717         }
718
719         return 0;
720
721 error:
722         _capture_channels = 0;
723         _playback_channels = 0;
724         free (_input_buffer); _input_buffer = NULL;
725         free (_output_buffer); _output_buffer = NULL;
726         return -1;
727 }
728
729 int
730 PortAudioIO::next_cycle (uint32_t n_samples)
731 {
732         bool xrun = false;
733         PaError err;
734         err = Pa_IsStreamActive (_stream);
735         if (err != 1) {
736                 //   0: inactive / aborted
737                 // < 0: error
738                 return -1;
739         }
740
741         // TODO, check drift..  process part with larger capacity first.
742         // Pa_GetStreamReadAvailable(_stream) < Pa_GetStreamWriteAvailable(_stream)
743
744         if (_playback_channels > 0) {
745                 err = Pa_WriteStream (_stream, _output_buffer, n_samples);
746                 if (err) xrun = true;
747         }
748
749         if (_capture_channels > 0) {
750                 err = Pa_ReadStream (_stream, _input_buffer, n_samples);
751                 if (err) {
752                         memset (_input_buffer, 0, sizeof(float) * n_samples * _capture_channels);
753                         xrun = true;
754                 }
755         }
756
757
758         return xrun ? 1 : 0;
759 }
760
761 std::string
762 PortAudioIO::get_input_channel_name (int device_id, uint32_t channel) const
763 {
764 #ifdef WITH_ASIO
765         const char* channel_name;
766
767         // This will return an error for non-ASIO devices so no need to check if
768         // the device_id corresponds to an ASIO device.
769         PaError err = PaAsio_GetInputChannelName (device_id, channel, &channel_name);
770
771         if (err == paNoError) {
772                 DEBUG_AUDIO (
773                     string_compose ("Input channel name for device %1, channel %2 is %3\n",
774                                     device_id,
775                                     channel,
776                                     channel_name));
777                 return channel_name;
778         }
779 #endif
780         return std::string();
781 }
782
783 std::string
784 PortAudioIO::get_output_channel_name (int device_id, uint32_t channel) const
785 {
786 #ifdef WITH_ASIO
787         const char* channel_name;
788
789         PaError err = PaAsio_GetOutputChannelName (device_id, channel, &channel_name);
790
791         if (err == paNoError) {
792                 DEBUG_AUDIO (
793                     string_compose ("Output channel name for device %1, channel %2 is %3\n",
794                                     device_id,
795                                     channel,
796                                     channel_name));
797                 return channel_name;
798         }
799 #endif
800         return std::string();
801 }
802
803 #ifdef INTERLEAVED_INPUT
804
805 int
806 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
807 {
808         assert(chn < _capture_channels);
809         const uint32_t stride = _capture_channels;
810         float *ptr = _input_buffer + chn;
811         while (n_samples-- > 0) {
812                 *input++ = *ptr;
813                 ptr += stride;
814         }
815         return 0;
816 }
817
818 #else
819
820 int
821 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
822 {
823         assert(chn < _capture_channels);
824         memcpy((void*)input, &(_input_buffer[chn * n_samples]), n_samples * sizeof(float));
825         return 0;
826 }
827
828 #endif
829
830
831 #ifdef INTERLEAVED_OUTPUT
832
833 int
834 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
835 {
836         assert(chn < _playback_channels);
837         const uint32_t stride = _playback_channels;
838         float *ptr = _output_buffer + chn;
839         while (n_samples-- > 0) {
840                 *ptr = *output++;
841                 ptr += stride;
842         }
843         return 0;
844 }
845
846 #else
847
848 int
849 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
850 {
851         assert(chn < _playback_channels);
852         memcpy((void*)&(_output_buffer[chn * n_samples]), (void*)output, n_samples * sizeof(float));
853         return 0;
854 }
855
856 #endif