if-sco.c 18 KB

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