tizen 2.3.1 release
[framework/connectivity/bluez.git] / android / client / if-sco.c
1 /*
2  * Copyright (C) 2014 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <pthread.h>
19 #include <unistd.h>
20 #include <math.h>
21
22 #include "if-main.h"
23 #include "../hal-utils.h"
24
25 audio_hw_device_t *if_audio_sco = NULL;
26 static struct audio_stream_out *stream_out = NULL;
27 static struct audio_stream_in *stream_in = NULL;
28
29 static size_t buffer_size = 0;
30 static size_t buffer_size_in = 0;
31 static pthread_t play_thread = 0;
32 static pthread_mutex_t outstream_mutex = PTHREAD_MUTEX_INITIALIZER;
33 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
34
35 enum state {
36         STATE_STOPPED,
37         STATE_STOPPING,
38         STATE_PLAYING,
39         STATE_SUSPENDED,
40         STATE_MAX
41 };
42
43 SINTMAP(audio_channel_mask_t, -1, "(AUDIO_CHANNEL_INVALID)")
44         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
45         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
46         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_CENTER),
47         DELEMENT(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
48         DELEMENT(AUDIO_CHANNEL_OUT_BACK_LEFT),
49         DELEMENT(AUDIO_CHANNEL_OUT_BACK_RIGHT),
50         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
51         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
52         DELEMENT(AUDIO_CHANNEL_OUT_BACK_CENTER),
53         DELEMENT(AUDIO_CHANNEL_OUT_SIDE_LEFT),
54         DELEMENT(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
55         DELEMENT(AUDIO_CHANNEL_OUT_TOP_CENTER),
56         DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
57         DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
58         DELEMENT(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
59         DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
60         DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
61         DELEMENT(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
62         DELEMENT(AUDIO_CHANNEL_OUT_MONO),
63         DELEMENT(AUDIO_CHANNEL_OUT_STEREO),
64         DELEMENT(AUDIO_CHANNEL_OUT_QUAD),
65 #if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
66         DELEMENT(AUDIO_CHANNEL_OUT_SURROUND),
67 #else
68         DELEMENT(AUDIO_CHANNEL_OUT_QUAD_BACK),
69         DELEMENT(AUDIO_CHANNEL_OUT_QUAD_SIDE),
70         DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_BACK),
71         DELEMENT(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
72 #endif
73         DELEMENT(AUDIO_CHANNEL_OUT_5POINT1),
74         DELEMENT(AUDIO_CHANNEL_OUT_7POINT1),
75         DELEMENT(AUDIO_CHANNEL_OUT_ALL),
76         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
77         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
78         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
79         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
80         DELEMENT(AUDIO_CHANNEL_OUT_FRONT_LEFT),
81 ENDMAP
82
83 SINTMAP(audio_format_t, -1, "(AUDIO_FORMAT_INVALID)")
84         DELEMENT(AUDIO_FORMAT_DEFAULT),
85         DELEMENT(AUDIO_FORMAT_PCM),
86         DELEMENT(AUDIO_FORMAT_MP3),
87         DELEMENT(AUDIO_FORMAT_AMR_NB),
88         DELEMENT(AUDIO_FORMAT_AMR_WB),
89         DELEMENT(AUDIO_FORMAT_AAC),
90         DELEMENT(AUDIO_FORMAT_HE_AAC_V1),
91         DELEMENT(AUDIO_FORMAT_HE_AAC_V2),
92         DELEMENT(AUDIO_FORMAT_VORBIS),
93         DELEMENT(AUDIO_FORMAT_MAIN_MASK),
94         DELEMENT(AUDIO_FORMAT_SUB_MASK),
95         DELEMENT(AUDIO_FORMAT_PCM_16_BIT),
96         DELEMENT(AUDIO_FORMAT_PCM_8_BIT),
97         DELEMENT(AUDIO_FORMAT_PCM_32_BIT),
98         DELEMENT(AUDIO_FORMAT_PCM_8_24_BIT),
99 ENDMAP
100
101 static int current_state = STATE_STOPPED;
102
103 #define SAMPLERATE 44100
104 static short sample[SAMPLERATE];
105 static uint16_t sample_pos;
106
107 static void init_p(int argc, const char **argv)
108 {
109         int err;
110         const hw_module_t *module;
111         audio_hw_device_t *device;
112
113         err = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "sco", &module);
114         if (err) {
115                 haltest_error("hw_get_module_by_class returned %d\n", err);
116                 return;
117         }
118
119         err = audio_hw_device_open(module, &device);
120         if (err) {
121                 haltest_error("audio_hw_device_open returned %d\n", err);
122                 return;
123         }
124
125         if_audio_sco = device;
126 }
127
128 static int feed_from_file(short *buffer, void *data)
129 {
130         FILE *in = data;
131         return fread(buffer, buffer_size, 1, in);
132 }
133
134 static int feed_from_generator(short *buffer, void *data)
135 {
136         size_t i = 0;
137         float volume = 0.5;
138         float *freq = data;
139         float f = 1;
140
141         if (freq)
142                 f = *freq;
143
144         /* buffer_size is in bytes but we are using buffer of shorts (2 bytes)*/
145         for (i = 0; i < buffer_size / sizeof(*buffer) - 1;) {
146                 if (sample_pos >= SAMPLERATE)
147                         sample_pos = sample_pos % SAMPLERATE;
148
149                 /* Use the same sample for both channels */
150                 buffer[i++] = sample[sample_pos] * volume;
151                 buffer[i++] = sample[sample_pos] * volume;
152
153                 sample_pos += f;
154         }
155
156         return buffer_size;
157 }
158
159 static int feed_from_in(short *buffer, void *data)
160 {
161         return stream_in->read(stream_in, buffer, buffer_size_in);
162 }
163
164 static void prepare_sample(void)
165 {
166         int x;
167         double s;
168
169         haltest_info("Preparing audio sample...\n");
170
171         for (x = 0; x < SAMPLERATE; x++) {
172                 /* prepare sinusoidal 1Hz sample */
173                 s = (2.0 * 3.14159) * ((double)x / SAMPLERATE);
174                 s = sin(s);
175
176                 /* remap <-1, 1> to signed 16bit PCM range */
177                 sample[x] = s * 32767;
178         }
179
180         sample_pos = 0;
181 }
182
183 static void mono_to_stereo_pcm16(const int16_t *in, int16_t *out, size_t samples)
184 {
185         size_t i;
186
187         for (i = 0; i < samples; i++) {
188                 out[2 * i] = in[i];
189                 out[2 * i + 1] = in[i];
190         }
191 }
192
193 static void *playback_thread(void *data)
194 {
195         int (*filbuff_cb) (short*, void*);
196         short buffer[buffer_size / sizeof(short)];
197         short buffer_in[buffer_size_in / sizeof(short)];
198         size_t len = 0;
199         ssize_t w_len = 0;
200         FILE *in = data;
201         void *cb_data = NULL;
202         float freq = 440.0;
203
204         /* Use file or fall back to generator */
205         if (in) {
206                 if (data == stream_in)
207                         filbuff_cb = feed_from_in;
208                 else {
209                         filbuff_cb = feed_from_file;
210                         cb_data = in;
211                 }
212         } else {
213                 prepare_sample();
214                 filbuff_cb = feed_from_generator;
215                 cb_data = &freq;
216         }
217
218         pthread_mutex_lock(&state_mutex);
219         current_state = STATE_PLAYING;
220         pthread_mutex_unlock(&state_mutex);
221
222         do {
223                 pthread_mutex_lock(&state_mutex);
224
225                 if (current_state == STATE_STOPPING) {
226                         haltest_info("Detected stopping\n");
227                         pthread_mutex_unlock(&state_mutex);
228                         break;
229                 } else if (current_state == STATE_SUSPENDED) {
230                         pthread_mutex_unlock(&state_mutex);
231                         usleep(500);
232                         continue;
233                 }
234
235                 pthread_mutex_unlock(&state_mutex);
236
237                 if (data && data == stream_in) {
238                         int chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
239                         int chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
240
241                         len = filbuff_cb(buffer_in, cb_data);
242
243                         if (chan_in == 1 && chan_out == 2) {
244                                 mono_to_stereo_pcm16(buffer_in,
245                                                         buffer,
246                                                         buffer_size_in / 2);
247                         }
248                 } else
249                         len = filbuff_cb(buffer, cb_data);
250
251                 pthread_mutex_lock(&outstream_mutex);
252                 if (!stream_out) {
253                         pthread_mutex_unlock(&outstream_mutex);
254                         break;
255                 }
256
257                 w_len = stream_out->write(stream_out, buffer, buffer_size);
258                 pthread_mutex_unlock(&outstream_mutex);
259         } while (len && w_len > 0);
260
261         if (in && data != stream_in)
262                 fclose(in);
263
264         pthread_mutex_lock(&state_mutex);
265         current_state = STATE_STOPPED;
266         pthread_mutex_unlock(&state_mutex);
267
268         haltest_info("Done playing.\n");
269
270         return NULL;
271 }
272
273 static void write_stereo_pcm16(const short *input, size_t len, FILE *out)
274 {
275         short sample[2];
276         size_t i;
277
278         for (i = 0; i < len / 2; i++) {
279                 sample[0] = input[i];
280                 sample[1] = input[i];
281
282                 fwrite(sample, sizeof(sample), 1, out);
283         }
284 }
285
286 static void *read_thread(void *data)
287 {
288         int (*filbuff_cb) (short*, void*) = feed_from_in;
289         short buffer[buffer_size_in / sizeof(short)];
290         ssize_t len = 0;
291         void *cb_data = NULL;
292         FILE *out = data;
293
294         pthread_mutex_lock(&state_mutex);
295         current_state = STATE_PLAYING;
296         pthread_mutex_unlock(&state_mutex);
297
298         do {
299                 pthread_mutex_lock(&state_mutex);
300
301                 if (current_state == STATE_STOPPING) {
302                         haltest_info("Detected stopping\n");
303                         pthread_mutex_unlock(&state_mutex);
304                         break;
305                 } else if (current_state == STATE_SUSPENDED) {
306                         pthread_mutex_unlock(&state_mutex);
307                         usleep(500);
308                         continue;
309                 }
310
311                 pthread_mutex_unlock(&state_mutex);
312
313                 len = filbuff_cb(buffer, cb_data);
314                 if (len < 0) {
315                         haltest_error("Error receiving SCO data");
316                         break;
317                 }
318
319                 haltest_info("Read %zd bytes\n", len);
320
321                 if (out) {
322                         write_stereo_pcm16(buffer, len, out);
323                         haltest_info("Written %zd bytes\n", len * 2);
324                 }
325         } while (len);
326
327         if (out)
328                 fclose(out);
329
330         pthread_mutex_lock(&state_mutex);
331         current_state = STATE_STOPPED;
332         pthread_mutex_unlock(&state_mutex);
333
334         haltest_info("Done reading.\n");
335
336         return NULL;
337 }
338
339 static void play_p(int argc, const char **argv)
340 {
341         const char *fname = NULL;
342         FILE *in = NULL;
343
344         RETURN_IF_NULL(if_audio_sco);
345         RETURN_IF_NULL(stream_out);
346
347         if (argc < 3) {
348                 haltest_error("Invalid audio file path.\n");
349                 haltest_info("Using sound generator.\n");
350         } else {
351                 fname = argv[2];
352                 in = fopen(fname, "r");
353
354                 if (in == NULL) {
355                         haltest_error("Cannot open file: %s\n", fname);
356                         return;
357                 }
358                 haltest_info("Playing file: %s\n", fname);
359         }
360
361         if (buffer_size == 0) {
362                 haltest_error("Invalid buffer size. Was stream_out opened?\n");
363                 goto fail;
364         }
365
366         pthread_mutex_lock(&state_mutex);
367         if (current_state != STATE_STOPPED) {
368                 haltest_error("Already playing or stream suspended!\n");
369                 pthread_mutex_unlock(&state_mutex);
370                 goto fail;
371         }
372         pthread_mutex_unlock(&state_mutex);
373
374         if (pthread_create(&play_thread, NULL, playback_thread, in) != 0) {
375                 haltest_error("Cannot create playback thread!\n");
376                 goto fail;
377         }
378
379         return;
380 fail:
381         if (in)
382                 fclose(in);
383 }
384
385 static void loop_p(int argc, const char **argv)
386 {
387         int chan_out, chan_in;
388
389         RETURN_IF_NULL(if_audio_sco);
390         RETURN_IF_NULL(stream_out);
391         RETURN_IF_NULL(stream_in);
392
393         chan_out = popcount(stream_out->common.get_channels(&stream_out->common));
394         chan_in = popcount(stream_in->common.get_channels(&stream_in->common));
395
396         if (!buffer_size || !buffer_size_in) {
397                 haltest_error("Invalid buffer sizes. Streams opened\n");
398                 return;
399         }
400
401         if (buffer_size / chan_out != buffer_size_in / chan_in) {
402                 haltest_error("read/write buffers differ, not supported\n");
403                 return;
404         }
405
406         pthread_mutex_lock(&state_mutex);
407         if (current_state != STATE_STOPPED) {
408                 haltest_error("Already playing or stream suspended!\n");
409                 pthread_mutex_unlock(&state_mutex);
410                 return;
411         }
412         pthread_mutex_unlock(&state_mutex);
413
414         if (pthread_create(&play_thread, NULL, playback_thread,
415                                                         stream_in) != 0)
416                 haltest_error("Cannot create playback thread!\n");
417 }
418
419 static void read_p(int argc, const char **argv)
420 {
421         const char *fname = NULL;
422         FILE *out = NULL;
423
424         RETURN_IF_NULL(if_audio_sco);
425         RETURN_IF_NULL(stream_in);
426
427         pthread_mutex_lock(&state_mutex);
428         if (current_state != STATE_STOPPED) {
429                 haltest_error("Already playing or stream suspended!\n");
430                 pthread_mutex_unlock(&state_mutex);
431                 return;
432         }
433         pthread_mutex_unlock(&state_mutex);
434
435         if (argc < 3) {
436                 haltest_error("Invalid audio file path.\n");
437                 haltest_info("Using read and through away\n");
438         } else {
439                 fname = argv[2];
440                 out = fopen(fname, "w");
441                 if (!out) {
442                         haltest_error("Cannot open file: %s\n", fname);
443                         return;
444                 }
445
446                 haltest_info("Reading to file: %s\n", fname);
447         }
448
449         if (!buffer_size_in) {
450                 haltest_error("Invalid buffer size.\n");
451                 goto failed;
452         }
453
454         if (pthread_create(&play_thread, NULL, read_thread, out) != 0) {
455                 haltest_error("Cannot create playback thread!\n");
456                 goto failed;
457         }
458
459         return;
460 failed:
461         if (out)
462                 fclose(out);
463 }
464
465 static void stop_p(int argc, const char **argv)
466 {
467         RETURN_IF_NULL(if_audio_sco);
468         RETURN_IF_NULL(play_thread);
469
470         pthread_mutex_lock(&state_mutex);
471         if (current_state == STATE_STOPPED || current_state == STATE_STOPPING) {
472                 pthread_mutex_unlock(&state_mutex);
473                 return;
474         }
475
476         if (stream_out) {
477                 pthread_mutex_lock(&outstream_mutex);
478                 stream_out->common.standby(&stream_out->common);
479                 pthread_mutex_unlock(&outstream_mutex);
480         }
481
482         current_state = STATE_STOPPING;
483         pthread_mutex_unlock(&state_mutex);
484
485         pthread_join(play_thread, NULL);
486         play_thread = 0;
487
488         haltest_info("Ended %s\n", __func__);
489 }
490
491 static void open_output_stream_p(int argc, const char **argv)
492 {
493         struct audio_config *config;
494         int err;
495
496         RETURN_IF_NULL(if_audio_sco);
497
498         pthread_mutex_lock(&state_mutex);
499         if (current_state == STATE_PLAYING) {
500                 haltest_error("Already playing!\n");
501                 pthread_mutex_unlock(&state_mutex);
502                 return;
503         }
504         pthread_mutex_unlock(&state_mutex);
505
506         if (argc < 3) {
507                 haltest_info("No sampling rate specified. Use default conf\n");
508                 config = NULL;
509         } else {
510                 config = calloc(1, sizeof(struct audio_config));
511                 if (!config)
512                         return;
513
514                 config->sample_rate = atoi(argv[2]);
515                 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
516                 config->format = AUDIO_FORMAT_PCM_16_BIT;
517         }
518
519 #if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
520         err = if_audio_sco->open_output_stream(if_audio_sco,
521                                                 0,
522                                                 AUDIO_DEVICE_OUT_ALL_SCO,
523                                                 AUDIO_OUTPUT_FLAG_NONE,
524                                                 config,
525                                                 &stream_out, NULL);
526 #else
527         err = if_audio_sco->open_output_stream(if_audio_sco,
528                                                 0,
529                                                 AUDIO_DEVICE_OUT_ALL_SCO,
530                                                 AUDIO_OUTPUT_FLAG_NONE,
531                                                 config,
532                                                 &stream_out);
533 #endif
534         if (err < 0) {
535                 haltest_error("open output stream returned %d\n", err);
536                 goto failed;
537         }
538
539         buffer_size = stream_out->common.get_buffer_size(&stream_out->common);
540         if (buffer_size == 0)
541                 haltest_error("Invalid buffer size received!\n");
542         else
543                 haltest_info("Using buffer size: %zu\n", buffer_size);
544 failed:
545         if (config)
546                 free(config);
547 }
548
549 static void close_output_stream_p(int argc, const char **argv)
550 {
551         RETURN_IF_NULL(if_audio_sco);
552         RETURN_IF_NULL(stream_out);
553
554         if (play_thread)
555                 stop_p(argc, argv);
556
557         if_audio_sco->close_output_stream(if_audio_sco, stream_out);
558
559         stream_out = NULL;
560         buffer_size = 0;
561 }
562
563 static void open_input_stream_p(int argc, const char **argv)
564 {
565         struct audio_config *config;
566         int err;
567
568         RETURN_IF_NULL(if_audio_sco);
569
570         pthread_mutex_lock(&state_mutex);
571         if (current_state == STATE_PLAYING) {
572                 haltest_error("Already playing!\n");
573                 pthread_mutex_unlock(&state_mutex);
574                 return;
575         }
576         pthread_mutex_unlock(&state_mutex);
577
578         if (argc < 3) {
579                 haltest_info("No sampling rate specified. Use default conf\n");
580                 config = NULL;
581         } else {
582                 config = calloc(1, sizeof(struct audio_config));
583                 if (!config)
584                         return;
585
586                 config->sample_rate = atoi(argv[2]);
587                 config->channel_mask = AUDIO_CHANNEL_OUT_MONO;
588                 config->format = AUDIO_FORMAT_PCM_16_BIT;
589         }
590
591 #if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
592         err = if_audio_sco->open_input_stream(if_audio_sco,
593                                                 0,
594                                                 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
595                                                 config,
596                                                 &stream_in, 0, NULL, 0);
597 #else
598         err = if_audio_sco->open_input_stream(if_audio_sco,
599                                                 0,
600                                                 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
601                                                 config,
602                                                 &stream_in);
603 #endif
604         if (err < 0) {
605                 haltest_error("open output stream returned %d\n", err);
606                 goto failed;
607         }
608
609         buffer_size_in = stream_in->common.get_buffer_size(&stream_in->common);
610         if (buffer_size_in == 0)
611                 haltest_error("Invalid buffer size received!\n");
612         else
613                 haltest_info("Using buffer size: %zu\n", buffer_size_in);
614 failed:
615         if (config)
616                 free(config);
617 }
618
619 static void close_input_stream_p(int argc, const char **argv)
620 {
621         RETURN_IF_NULL(if_audio_sco);
622         RETURN_IF_NULL(stream_in);
623
624         if (play_thread)
625                 stop_p(argc, argv);
626
627         if_audio_sco->close_input_stream(if_audio_sco, stream_in);
628
629         stream_in = NULL;
630         buffer_size_in = 0;
631 }
632
633 static void cleanup_p(int argc, const char **argv)
634 {
635         int err;
636
637         RETURN_IF_NULL(if_audio_sco);
638
639         pthread_mutex_lock(&state_mutex);
640         if (current_state != STATE_STOPPED) {
641                 pthread_mutex_unlock(&state_mutex);
642                 close_output_stream_p(0, NULL);
643         } else {
644                 pthread_mutex_unlock(&state_mutex);
645         }
646
647         err = audio_hw_device_close(if_audio_sco);
648         if (err < 0) {
649                 haltest_error("audio_hw_device_close returned %d\n", err);
650                 return;
651         }
652
653         if_audio_sco = NULL;
654 }
655
656 static void suspend_p(int argc, const char **argv)
657 {
658         RETURN_IF_NULL(if_audio_sco);
659         RETURN_IF_NULL(stream_out);
660
661         pthread_mutex_lock(&state_mutex);
662         if (current_state != STATE_PLAYING) {
663                 pthread_mutex_unlock(&state_mutex);
664                 return;
665         }
666         current_state = STATE_SUSPENDED;
667         pthread_mutex_unlock(&state_mutex);
668
669         pthread_mutex_lock(&outstream_mutex);
670         stream_out->common.standby(&stream_out->common);
671         pthread_mutex_unlock(&outstream_mutex);
672 }
673
674 static void resume_p(int argc, const char **argv)
675 {
676         RETURN_IF_NULL(if_audio_sco);
677         RETURN_IF_NULL(stream_out);
678
679         pthread_mutex_lock(&state_mutex);
680         if (current_state == STATE_SUSPENDED)
681                 current_state = STATE_PLAYING;
682         pthread_mutex_unlock(&state_mutex);
683 }
684
685 static void get_latency_p(int argc, const char **argv)
686 {
687         RETURN_IF_NULL(if_audio_sco);
688         RETURN_IF_NULL(stream_out);
689
690         haltest_info("Output audio stream latency: %d\n",
691                                         stream_out->get_latency(stream_out));
692 }
693
694 static void get_buffer_size_p(int argc, const char **argv)
695 {
696         RETURN_IF_NULL(if_audio_sco);
697         RETURN_IF_NULL(stream_out);
698
699         haltest_info("Current output buffer size: %zu\n",
700                 stream_out->common.get_buffer_size(&stream_out->common));
701 }
702
703 static void get_channels_p(int argc, const char **argv)
704 {
705         audio_channel_mask_t channels;
706
707         RETURN_IF_NULL(if_audio_sco);
708         RETURN_IF_NULL(stream_out);
709
710         channels = stream_out->common.get_channels(&stream_out->common);
711
712         haltest_info("Channels: %s\n", audio_channel_mask_t2str(channels));
713 }
714
715 static void get_format_p(int argc, const char **argv)
716 {
717         audio_format_t format;
718
719         RETURN_IF_NULL(if_audio_sco);
720         RETURN_IF_NULL(stream_out);
721
722         format = stream_out->common.get_format(&stream_out->common);
723
724         haltest_info("Format: %s\n", audio_format_t2str(format));
725 }
726
727 static void get_sample_rate_p(int argc, const char **argv)
728 {
729         RETURN_IF_NULL(if_audio_sco);
730         RETURN_IF_NULL(stream_out);
731
732         haltest_info("Current sample rate: %d\n",
733                 stream_out->common.get_sample_rate(&stream_out->common));
734 }
735
736 static void get_parameters_p(int argc, const char **argv)
737 {
738         const char *keystr;
739
740         RETURN_IF_NULL(if_audio_sco);
741         RETURN_IF_NULL(stream_out);
742
743         if (argc < 3) {
744                 haltest_info("No keys given.\n");
745                 keystr = "";
746         } else {
747                 keystr = argv[2];
748         }
749
750         haltest_info("Current parameters: %s\n",
751                         stream_out->common.get_parameters(&stream_out->common,
752                                                                 keystr));
753 }
754
755 static void set_parameters_p(int argc, const char **argv)
756 {
757         RETURN_IF_NULL(if_audio_sco);
758         RETURN_IF_NULL(stream_out);
759
760         if (argc < 3) {
761                 haltest_error("No key=value; pairs given.\n");
762                 return;
763         }
764
765         stream_out->common.set_parameters(&stream_out->common, argv[2]);
766 }
767
768 static void set_sample_rate_p(int argc, const char **argv)
769 {
770         RETURN_IF_NULL(if_audio_sco);
771         RETURN_IF_NULL(stream_out);
772
773         if (argc < 3)
774                 return;
775
776         stream_out->common.set_sample_rate(&stream_out->common, atoi(argv[2]));
777 }
778
779 static void init_check_p(int argc, const char **argv)
780 {
781         RETURN_IF_NULL(if_audio_sco);
782
783         haltest_info("Init check result: %d\n",
784                                         if_audio_sco->init_check(if_audio_sco));
785 }
786
787 static struct method methods[] = {
788         STD_METHOD(init),
789         STD_METHOD(cleanup),
790         STD_METHODH(open_output_stream, "sample_rate"),
791         STD_METHOD(close_output_stream),
792         STD_METHODH(open_input_stream, "sampling rate"),
793         STD_METHOD(close_input_stream),
794         STD_METHODH(play, "<path to pcm file>"),
795         STD_METHOD(read),
796         STD_METHOD(loop),
797         STD_METHOD(stop),
798         STD_METHOD(suspend),
799         STD_METHOD(resume),
800         STD_METHOD(get_latency),
801         STD_METHOD(get_buffer_size),
802         STD_METHOD(get_channels),
803         STD_METHOD(get_format),
804         STD_METHOD(get_sample_rate),
805         STD_METHODH(get_parameters, "<closing>"),
806         STD_METHODH(set_parameters, "<closing=value>"),
807         STD_METHODH(set_sample_rate, "<sample rate>"),
808         STD_METHOD(init_check),
809         END_METHOD
810 };
811
812 const struct interface sco_if = {
813         .name = "sco",
814         .methods = methods
815 };