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