audio.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. /****************************************************************************
  2. * audio/audio.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <stdint.h>
  27. #include <stdbool.h>
  28. #include <stdlib.h>
  29. #include <unistd.h>
  30. #include <string.h>
  31. #include <fcntl.h>
  32. #include <assert.h>
  33. #include <errno.h>
  34. #include <debug.h>
  35. #include <nuttx/kmalloc.h>
  36. #include <nuttx/mqueue.h>
  37. #include <nuttx/arch.h>
  38. #include <nuttx/fs/fs.h>
  39. #include <nuttx/audio/audio.h>
  40. #include <nuttx/semaphore.h>
  41. #include <arch/irq.h>
  42. #ifdef CONFIG_AUDIO
  43. /****************************************************************************
  44. * Pre-processor Definitions
  45. ****************************************************************************/
  46. /* Debug ********************************************************************/
  47. /* Non-standard debug that may be enabled just for testing Audio */
  48. #ifndef AUDIO_MAX_DEVICE_PATH
  49. # define AUDIO_MAX_DEVICE_PATH 32
  50. #endif
  51. #ifndef CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO
  52. # define CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO 1
  53. #endif
  54. /****************************************************************************
  55. * Private Type Definitions
  56. ****************************************************************************/
  57. /* This structure describes the state of the upper half driver */
  58. struct audio_upperhalf_s
  59. {
  60. uint8_t crefs; /* The number of times the device has been opened */
  61. volatile bool started; /* True: playback is active */
  62. sem_t exclsem; /* Supports mutual exclusion */
  63. FAR struct audio_lowerhalf_s *dev; /* lower-half state */
  64. struct file *usermq; /* User mode app's message queue */
  65. };
  66. /****************************************************************************
  67. * Private Function Prototypes
  68. ****************************************************************************/
  69. static int audio_open(FAR struct file *filep);
  70. static int audio_close(FAR struct file *filep);
  71. static ssize_t audio_read(FAR struct file *filep,
  72. FAR char *buffer,
  73. size_t buflen);
  74. static ssize_t audio_write(FAR struct file *filep,
  75. FAR const char *buffer,
  76. size_t buflen);
  77. static int audio_ioctl(FAR struct file *filep,
  78. int cmd,
  79. unsigned long arg);
  80. #ifdef CONFIG_AUDIO_MULTI_SESSION
  81. static int audio_start(FAR struct audio_upperhalf_s *upper,
  82. FAR void *session);
  83. static void audio_callback(FAR void *priv,
  84. uint16_t reason,
  85. FAR struct ap_buffer_s *apb,
  86. uint16_t status,
  87. FAR void *session);
  88. #else
  89. static int audio_start(FAR struct audio_upperhalf_s *upper);
  90. static void audio_callback(FAR void *priv,
  91. uint16_t reason,
  92. FAR struct ap_buffer_s *apb,
  93. uint16_t status);
  94. #endif /* CONFIG_AUDIO_MULTI_SESSION */
  95. /****************************************************************************
  96. * Private Data
  97. ****************************************************************************/
  98. static const struct file_operations g_audioops =
  99. {
  100. audio_open, /* open */
  101. audio_close, /* close */
  102. audio_read, /* read */
  103. audio_write, /* write */
  104. NULL, /* seek */
  105. audio_ioctl, /* ioctl */
  106. NULL /* poll */
  107. };
  108. /****************************************************************************
  109. * Private Functions
  110. ****************************************************************************/
  111. /****************************************************************************
  112. * Name: audio_open
  113. *
  114. * Description:
  115. * This function is called whenever the Audio device is opened.
  116. *
  117. ****************************************************************************/
  118. static int audio_open(FAR struct file *filep)
  119. {
  120. FAR struct inode *inode = filep->f_inode;
  121. FAR struct audio_upperhalf_s *upper = inode->i_private;
  122. uint8_t tmp;
  123. int ret;
  124. audinfo("crefs: %d\n", upper->crefs);
  125. /* Get exclusive access to the device structures */
  126. ret = nxsem_wait(&upper->exclsem);
  127. if (ret < 0)
  128. {
  129. ret = -errno;
  130. goto errout;
  131. }
  132. /* Increment the count of references to the device. If this the first
  133. * time that the driver has been opened for this device, then initialize
  134. * the device.
  135. */
  136. tmp = upper->crefs + 1;
  137. if (tmp == 0)
  138. {
  139. /* More than 255 opens; uint8_t overflows to zero */
  140. ret = -EMFILE;
  141. goto errout_with_sem;
  142. }
  143. /* Save the new open count on success */
  144. upper->crefs = tmp;
  145. ret = OK;
  146. errout_with_sem:
  147. nxsem_post(&upper->exclsem);
  148. errout:
  149. return ret;
  150. }
  151. /****************************************************************************
  152. * Name: audio_close
  153. *
  154. * Description:
  155. * This function is called when the Audio device is closed.
  156. *
  157. ****************************************************************************/
  158. static int audio_close(FAR struct file *filep)
  159. {
  160. FAR struct inode *inode = filep->f_inode;
  161. FAR struct audio_upperhalf_s *upper = inode->i_private;
  162. int ret;
  163. audinfo("crefs: %d\n", upper->crefs);
  164. /* Get exclusive access to the device structures */
  165. ret = nxsem_wait(&upper->exclsem);
  166. if (ret < 0)
  167. {
  168. ret = -errno;
  169. goto errout;
  170. }
  171. /* Decrement the references to the driver. If the reference count will
  172. * decrement to 0, then uninitialize the driver.
  173. */
  174. if (upper->crefs > 1)
  175. {
  176. upper->crefs--;
  177. }
  178. else
  179. {
  180. FAR struct audio_lowerhalf_s *lower = upper->dev;
  181. /* There are no more references to the port */
  182. upper->crefs = 0;
  183. /* Disable the Audio device */
  184. DEBUGASSERT(lower->ops->shutdown != NULL);
  185. audinfo("calling shutdown\n");
  186. lower->ops->shutdown(lower);
  187. upper->usermq = NULL;
  188. }
  189. ret = OK;
  190. nxsem_post(&upper->exclsem);
  191. errout:
  192. return ret;
  193. }
  194. /****************************************************************************
  195. * Name: audio_read
  196. *
  197. * Description:
  198. * A dummy read method. This is provided only to satsify the VFS layer.
  199. *
  200. ****************************************************************************/
  201. static ssize_t audio_read(FAR struct file *filep,
  202. FAR char *buffer,
  203. size_t buflen)
  204. {
  205. FAR struct inode *inode = filep->f_inode;
  206. FAR struct audio_upperhalf_s *upper = inode->i_private;
  207. FAR struct audio_lowerhalf_s *lower = upper->dev;
  208. /* TODO: Should we check permissions here? */
  209. /* Audio read operations get passed directly to the lower-level */
  210. if (lower->ops->read != NULL)
  211. {
  212. return lower->ops->read(lower, buffer, buflen);
  213. }
  214. return 0;
  215. }
  216. /****************************************************************************
  217. * Name: audio_write
  218. *
  219. * Description:
  220. * A dummy write method. This is provided only to satsify the VFS layer.
  221. *
  222. ****************************************************************************/
  223. static ssize_t audio_write(FAR struct file *filep,
  224. FAR const char *buffer,
  225. size_t buflen)
  226. {
  227. FAR struct inode *inode = filep->f_inode;
  228. FAR struct audio_upperhalf_s *upper = inode->i_private;
  229. FAR struct audio_lowerhalf_s *lower = upper->dev;
  230. /* TODO: Should we check permissions here? */
  231. /* Audio write operations get passed directly to the lower-level */
  232. if (lower->ops->write != NULL)
  233. {
  234. return lower->ops->write(lower, buffer, buflen);
  235. }
  236. return 0;
  237. }
  238. /****************************************************************************
  239. * Name: audio_start
  240. *
  241. * Description:
  242. * Handle the AUDIOIOC_START ioctl command
  243. *
  244. ****************************************************************************/
  245. #ifdef CONFIG_AUDIO_MULTI_SESSION
  246. static int audio_start(FAR struct audio_upperhalf_s *upper,
  247. FAR void *session)
  248. #else
  249. static int audio_start(FAR struct audio_upperhalf_s *upper)
  250. #endif
  251. {
  252. FAR struct audio_lowerhalf_s *lower = upper->dev;
  253. int ret = OK;
  254. DEBUGASSERT(upper != NULL && lower->ops->start != NULL);
  255. /* Verify that the Audio is not already running */
  256. if (!upper->started)
  257. {
  258. /* Invoke the bottom half method to start the audio stream */
  259. #ifdef CONFIG_AUDIO_MULTI_SESSION
  260. ret = lower->ops->start(lower, session);
  261. #else
  262. ret = lower->ops->start(lower);
  263. #endif
  264. /* A return value of zero means that the audio stream was started
  265. * successfully.
  266. */
  267. if (ret == OK)
  268. {
  269. /* Indicate that the audio stream has started */
  270. upper->started = true;
  271. }
  272. }
  273. return ret;
  274. }
  275. /****************************************************************************
  276. * Name: audio_ioctl
  277. *
  278. * Description:
  279. * The standard ioctl method. This is where ALL of the Audio work is done.
  280. *
  281. ****************************************************************************/
  282. static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  283. {
  284. FAR struct inode *inode = filep->f_inode;
  285. FAR struct audio_upperhalf_s *upper = inode->i_private;
  286. FAR struct audio_lowerhalf_s *lower = upper->dev;
  287. FAR struct audio_buf_desc_s *bufdesc;
  288. #ifdef CONFIG_AUDIO_MULTI_SESSION
  289. FAR void *session;
  290. #endif
  291. int ret;
  292. audinfo("cmd: %d arg: %ld\n", cmd, arg);
  293. /* Get exclusive access to the device structures */
  294. ret = nxsem_wait(&upper->exclsem);
  295. if (ret < 0)
  296. {
  297. return ret;
  298. }
  299. /* Handle built-in ioctl commands */
  300. switch (cmd)
  301. {
  302. /* AUDIOIOC_GETCAPS - Get the audio device capabilities.
  303. *
  304. * ioctl argument: A pointer to the audio_caps_s structure.
  305. */
  306. case AUDIOIOC_GETCAPS:
  307. {
  308. FAR struct audio_caps_s *caps =
  309. (FAR struct audio_caps_s *)((uintptr_t)arg);
  310. DEBUGASSERT(lower->ops->getcaps != NULL);
  311. audinfo("AUDIOIOC_GETCAPS: Device=%d\n", caps->ac_type);
  312. /* Call the lower-half driver capabilities handler */
  313. ret = lower->ops->getcaps(lower, caps->ac_type, caps);
  314. }
  315. break;
  316. case AUDIOIOC_CONFIGURE:
  317. {
  318. FAR const struct audio_caps_desc_s *caps =
  319. (FAR const struct audio_caps_desc_s *)((uintptr_t)arg);
  320. DEBUGASSERT(lower->ops->configure != NULL);
  321. audinfo("AUDIOIOC_INITIALIZE: Device=%d\n", caps->caps.ac_type);
  322. /* Call the lower-half driver configure handler */
  323. #ifdef CONFIG_AUDIO_MULTI_SESSION
  324. ret = lower->ops->configure(lower, caps->session, &caps->caps);
  325. #else
  326. ret = lower->ops->configure(lower, &caps->caps);
  327. #endif
  328. }
  329. break;
  330. case AUDIOIOC_SHUTDOWN:
  331. {
  332. DEBUGASSERT(lower->ops->shutdown != NULL);
  333. audinfo("AUDIOIOC_SHUTDOWN\n");
  334. /* Call the lower-half driver initialize handler */
  335. ret = lower->ops->shutdown(lower);
  336. }
  337. break;
  338. /* AUDIOIOC_START - Start the audio stream.
  339. * The AUDIOIOC_SETCHARACTERISTICS
  340. * command must have previously been sent.
  341. *
  342. * ioctl argument: Audio session
  343. */
  344. case AUDIOIOC_START:
  345. {
  346. audinfo("AUDIOIOC_START\n");
  347. DEBUGASSERT(lower->ops->start != NULL);
  348. /* Start the audio stream */
  349. #ifdef CONFIG_AUDIO_MULTI_SESSION
  350. session = (FAR void *) arg;
  351. ret = audio_start(upper, session);
  352. #else
  353. ret = audio_start(upper);
  354. #endif
  355. }
  356. break;
  357. /* AUDIOIOC_STOP - Stop the audio stream.
  358. *
  359. * ioctl argument: Audio session
  360. */
  361. #ifndef CONFIG_AUDIO_EXCLUDE_STOP
  362. case AUDIOIOC_STOP:
  363. {
  364. audinfo("AUDIOIOC_STOP\n");
  365. DEBUGASSERT(lower->ops->stop != NULL);
  366. if (upper->started)
  367. {
  368. #ifdef CONFIG_AUDIO_MULTI_SESSION
  369. session = (FAR void *) arg;
  370. ret = lower->ops->stop(lower, session);
  371. #else
  372. ret = lower->ops->stop(lower);
  373. #endif
  374. upper->started = false;
  375. }
  376. }
  377. break;
  378. #endif /* CONFIG_AUDIO_EXCLUDE_STOP */
  379. /* AUDIOIOC_PAUSE - Pause the audio stream.
  380. *
  381. * ioctl argument: Audio session
  382. */
  383. #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
  384. case AUDIOIOC_PAUSE:
  385. {
  386. audinfo("AUDIOIOC_PAUSE\n");
  387. DEBUGASSERT(lower->ops->pause != NULL);
  388. if (upper->started)
  389. {
  390. #ifdef CONFIG_AUDIO_MULTI_SESSION
  391. session = (FAR void *) arg;
  392. ret = lower->ops->pause(lower, session);
  393. #else
  394. ret = lower->ops->pause(lower);
  395. #endif
  396. }
  397. }
  398. break;
  399. /* AUDIOIOC_RESUME - Resume the audio stream.
  400. *
  401. * ioctl argument: Audio session
  402. */
  403. case AUDIOIOC_RESUME:
  404. {
  405. audinfo("AUDIOIOC_RESUME\n");
  406. DEBUGASSERT(lower->ops->resume != NULL);
  407. if (upper->started)
  408. {
  409. #ifdef CONFIG_AUDIO_MULTI_SESSION
  410. session = (FAR void *) arg;
  411. ret = lower->ops->resume(lower, session);
  412. #else
  413. ret = lower->ops->resume(lower);
  414. #endif
  415. }
  416. }
  417. break;
  418. #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
  419. /* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer
  420. *
  421. * ioctl argument: pointer to an audio_buf_desc_s structure
  422. */
  423. case AUDIOIOC_ALLOCBUFFER:
  424. {
  425. audinfo("AUDIOIOC_ALLOCBUFFER\n");
  426. bufdesc = (FAR struct audio_buf_desc_s *) arg;
  427. if (lower->ops->allocbuffer)
  428. {
  429. ret = lower->ops->allocbuffer(lower, bufdesc);
  430. }
  431. else
  432. {
  433. /* Perform a simple kumm_malloc operation assuming 1 session */
  434. ret = apb_alloc(bufdesc);
  435. }
  436. }
  437. break;
  438. /* AUDIOIOC_FREEBUFFER - Free an audio buffer
  439. *
  440. * ioctl argument: pointer to an audio_buf_desc_s structure
  441. */
  442. case AUDIOIOC_FREEBUFFER:
  443. {
  444. audinfo("AUDIOIOC_FREEBUFFER\n");
  445. bufdesc = (FAR struct audio_buf_desc_s *) arg;
  446. if (lower->ops->freebuffer)
  447. {
  448. ret = lower->ops->freebuffer(lower, bufdesc);
  449. }
  450. else
  451. {
  452. /* Perform a simple apb_free operation */
  453. DEBUGASSERT(bufdesc->u.buffer != NULL);
  454. apb_free(bufdesc->u.buffer);
  455. ret = sizeof(struct audio_buf_desc_s);
  456. }
  457. }
  458. break;
  459. /* AUDIOIOC_ENQUEUEBUFFER - Enqueue an audio buffer
  460. *
  461. * ioctl argument: pointer to an audio_buf_desc_s structure
  462. */
  463. case AUDIOIOC_ENQUEUEBUFFER:
  464. {
  465. audinfo("AUDIOIOC_ENQUEUEBUFFER\n");
  466. DEBUGASSERT(lower->ops->enqueuebuffer != NULL);
  467. bufdesc = (FAR struct audio_buf_desc_s *) arg;
  468. ret = lower->ops->enqueuebuffer(lower, bufdesc->u.buffer);
  469. }
  470. break;
  471. /* AUDIOIOC_REGISTERMQ - Register a client Message Queue
  472. *
  473. * TODO: This needs to have multi session support.
  474. */
  475. case AUDIOIOC_REGISTERMQ:
  476. {
  477. audinfo("AUDIOIOC_REGISTERMQ\n");
  478. ret = fs_getfilep((mqd_t)arg, &upper->usermq);
  479. }
  480. break;
  481. /* AUDIOIOC_UNREGISTERMQ - Register a client Message Queue
  482. *
  483. * TODO: This needs to have multi session support.
  484. */
  485. case AUDIOIOC_UNREGISTERMQ:
  486. {
  487. audinfo("AUDIOIOC_UNREGISTERMQ\n");
  488. upper->usermq = NULL;
  489. ret = OK;
  490. }
  491. break;
  492. /* AUDIOIOC_RESERVE - Reserve a session with the driver
  493. *
  494. * ioctl argument - pointer to receive the session context
  495. */
  496. case AUDIOIOC_RESERVE:
  497. {
  498. audinfo("AUDIOIOC_RESERVE\n");
  499. DEBUGASSERT(lower->ops->reserve != NULL);
  500. /* Call lower-half to perform the reservation */
  501. #ifdef CONFIG_AUDIO_MULTI_SESSION
  502. ret = lower->ops->reserve(lower, (FAR void **) arg);
  503. #else
  504. ret = lower->ops->reserve(lower);
  505. #endif
  506. }
  507. break;
  508. /* AUDIOIOC_RESERVE - Reserve a session with the driver
  509. *
  510. * ioctl argument - pointer to receive the session context
  511. */
  512. case AUDIOIOC_RELEASE:
  513. {
  514. audinfo("AUDIOIOC_RELEASE\n");
  515. DEBUGASSERT(lower->ops->release != NULL);
  516. /* Call lower-half to perform the release */
  517. #ifdef CONFIG_AUDIO_MULTI_SESSION
  518. ret = lower->ops->release(lower, (FAR void *) arg);
  519. #else
  520. ret = lower->ops->release(lower);
  521. #endif
  522. }
  523. break;
  524. /* Any unrecognized IOCTL commands might be
  525. * platform-specific ioctl commands
  526. */
  527. default:
  528. {
  529. audinfo("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg);
  530. DEBUGASSERT(lower->ops->ioctl != NULL);
  531. ret = lower->ops->ioctl(lower, cmd, arg);
  532. }
  533. break;
  534. }
  535. nxsem_post(&upper->exclsem);
  536. return ret;
  537. }
  538. /****************************************************************************
  539. * Name: audio_dequeuebuffer
  540. *
  541. * Description:
  542. * Dequeues a previously enqueued Audio Pipeline Buffer.
  543. *
  544. * 1. The upper half driver calls the enqueuebuffer method, providing the
  545. * lower half driver with the ab_buffer to process.
  546. * 2. The lower half driver's enqueuebuffer will either processes the
  547. * buffer directly, or more likely add it to a queue for processing
  548. * by a background thread or worker task.
  549. * 3. When the lower half driver has completed processing of the enqueued
  550. * ab_buffer, it will call this routine to indicate processing of the
  551. * buffer is complete.
  552. * 4. When this routine is called, it will check if any threads are waiting
  553. * to enqueue additional buffers and "wake them up" for further
  554. * processing.
  555. *
  556. * Input Parameters:
  557. * handle - This is the handle that was provided to the lower-half
  558. * start() method.
  559. * apb - A pointer to the previsously enqueued ap_buffer_s
  560. * status - Status of the dequeue operation
  561. *
  562. * Returned Value:
  563. * None
  564. *
  565. * Assumptions:
  566. * This function may be called from an interrupt handler.
  567. *
  568. ****************************************************************************/
  569. #ifdef CONFIG_AUDIO_MULTI_SESSION
  570. static inline void audio_dequeuebuffer(FAR struct audio_upperhalf_s *upper,
  571. FAR struct ap_buffer_s *apb, uint16_t status,
  572. FAR void *session)
  573. #else
  574. static inline void audio_dequeuebuffer(FAR struct audio_upperhalf_s *upper,
  575. FAR struct ap_buffer_s *apb, uint16_t status)
  576. #endif
  577. {
  578. struct audio_msg_s msg;
  579. audinfo("Entry\n");
  580. /* Send a dequeue message to the user if a message queue is registered */
  581. if (upper->usermq != NULL)
  582. {
  583. msg.msg_id = AUDIO_MSG_DEQUEUE;
  584. msg.u.ptr = apb;
  585. #ifdef CONFIG_AUDIO_MULTI_SESSION
  586. msg.session = session;
  587. #endif
  588. apb->flags |= AUDIO_APB_DEQUEUED;
  589. file_mq_send(upper->usermq, (FAR const char *)&msg, sizeof(msg),
  590. CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO);
  591. }
  592. }
  593. /****************************************************************************
  594. * Name: audio_complete
  595. *
  596. * Description:
  597. * Send an AUDIO_MSG_COMPLETE message to the client to indicate that the
  598. * active playback has completed. The lower-half driver initiates this
  599. * call via its callback pointer to our upper-half driver.
  600. *
  601. ****************************************************************************/
  602. #ifdef CONFIG_AUDIO_MULTI_SESSION
  603. static inline void audio_complete(FAR struct audio_upperhalf_s *upper,
  604. FAR struct ap_buffer_s *apb, uint16_t status,
  605. FAR void *session)
  606. #else
  607. static inline void audio_complete(FAR struct audio_upperhalf_s *upper,
  608. FAR struct ap_buffer_s *apb, uint16_t status)
  609. #endif
  610. {
  611. struct audio_msg_s msg;
  612. audinfo("Entry\n");
  613. /* Send a dequeue message to the user if a message queue is registered */
  614. upper->started = false;
  615. if (upper->usermq != NULL)
  616. {
  617. msg.msg_id = AUDIO_MSG_COMPLETE;
  618. msg.u.ptr = NULL;
  619. #ifdef CONFIG_AUDIO_MULTI_SESSION
  620. msg.session = session;
  621. #endif
  622. file_mq_send(upper->usermq, (FAR const char *)&msg, sizeof(msg),
  623. CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO);
  624. }
  625. }
  626. /****************************************************************************
  627. * Name: audio_message
  628. *
  629. * Description:
  630. * Send an custom message to the client to indicate that the
  631. * active message has delivered. The lower-half driver initiates this
  632. * call via its callback pointer to our upper-half driver.
  633. *
  634. ****************************************************************************/
  635. #ifdef CONFIG_AUDIO_MULTI_SESSION
  636. static inline void audio_message(FAR struct audio_upperhalf_s *upper,
  637. FAR struct ap_buffer_s *apb, uint16_t status,
  638. FAR void *session)
  639. #else
  640. static inline void audio_message(FAR struct audio_upperhalf_s *upper,
  641. FAR struct ap_buffer_s *apb, uint16_t status)
  642. #endif
  643. {
  644. struct audio_msg_s *msg = (FAR struct audio_msg_s *)apb;
  645. /* Send a message to the user if a message queue is registered */
  646. if (upper->usermq != NULL)
  647. {
  648. #ifdef CONFIG_AUDIO_MULTI_SESSION
  649. msg->session = session;
  650. #endif
  651. file_mq_send(upper->usermq, (FAR const char *)msg, sizeof(*msg),
  652. CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO);
  653. }
  654. }
  655. /****************************************************************************
  656. * Name: audio_callback
  657. *
  658. * Description:
  659. * Provides a callback interface for lower-half drivers to call to the
  660. * upper-half for buffer dequeueing, error reporting, etc.
  661. *
  662. * Input Parameters:
  663. * priv - Private context data owned by the upper-half
  664. * reason - The reason code for the callback
  665. * apb - A pointer to the previsously enqueued ap_buffer_s
  666. * status - Status information associated with the callback
  667. *
  668. * Returned Value:
  669. * None
  670. *
  671. * Assumptions:
  672. * This function may be called from an interrupt handler.
  673. *
  674. ****************************************************************************/
  675. #ifdef CONFIG_AUDIO_MULTI_SESSION
  676. static void audio_callback(FAR void *handle, uint16_t reason,
  677. FAR struct ap_buffer_s *apb, uint16_t status,
  678. FAR void *session)
  679. #else
  680. static void audio_callback(FAR void *handle, uint16_t reason,
  681. FAR struct ap_buffer_s *apb, uint16_t status)
  682. #endif
  683. {
  684. FAR struct audio_upperhalf_s *upper =
  685. (FAR struct audio_upperhalf_s *)handle;
  686. audinfo("Entry\n");
  687. /* Perform operation based on reason code */
  688. switch (reason)
  689. {
  690. case AUDIO_CALLBACK_DEQUEUE:
  691. {
  692. /* Call the dequeue routine */
  693. #ifdef CONFIG_AUDIO_MULTI_SESSION
  694. audio_dequeuebuffer(upper, apb, status, session);
  695. #else
  696. audio_dequeuebuffer(upper, apb, status);
  697. #endif
  698. break;
  699. }
  700. /* Lower-half I/O error occurred */
  701. case AUDIO_CALLBACK_IOERR:
  702. {
  703. }
  704. break;
  705. /* Lower-half driver has completed a playback */
  706. case AUDIO_CALLBACK_COMPLETE:
  707. {
  708. /* Send a complete message to the user if a message queue
  709. * is registered
  710. */
  711. #ifdef CONFIG_AUDIO_MULTI_SESSION
  712. audio_complete(upper, apb, status, session);
  713. #else
  714. audio_complete(upper, apb, status);
  715. #endif
  716. }
  717. break;
  718. case AUDIO_CALLBACK_MESSAGE:
  719. {
  720. #ifdef CONFIG_AUDIO_MULTI_SESSION
  721. audio_message(upper, apb, status, session);
  722. #else
  723. audio_message(upper, apb, status);
  724. #endif
  725. }
  726. break;
  727. default:
  728. {
  729. auderr("ERROR: Unknown callback reason code %d\n", reason);
  730. break;
  731. }
  732. }
  733. }
  734. /****************************************************************************
  735. * Public Functions
  736. ****************************************************************************/
  737. /****************************************************************************
  738. * Name: audio_register
  739. *
  740. * Description:
  741. * This function binds an instance of a "lower half" audio driver with the
  742. * "upper half" Audio device and registers that device so that can be used
  743. * by application code.
  744. *
  745. * When this function is called, the "lower half" driver should be in the
  746. * reset state (as if the shutdown() method had already been called).
  747. *
  748. * Input Parameters:
  749. * path - The full path to the driver to be registers in the NuttX pseudo-
  750. * filesystem. The recommended convention is to name Audio drivers
  751. * based on the function they provide, such as "/dev/pcm0", "/dev/mp31",
  752. * etc.
  753. * dev - A pointer to an instance of lower half audio driver.
  754. * This instance is bound to the Audio driver and must persists as long
  755. * as the driver persists.
  756. *
  757. * Returned Value:
  758. * Zero on success; a negated errno value on failure.
  759. *
  760. ****************************************************************************/
  761. int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev)
  762. {
  763. FAR struct audio_upperhalf_s *upper;
  764. char path[AUDIO_MAX_DEVICE_PATH];
  765. static bool dev_audio_created = false;
  766. #ifndef CONFIG_AUDIO_CUSTOM_DEV_PATH
  767. FAR const char *devname = "/dev/audio";
  768. #elif !defined(CONFIG_AUDIO_DEV_ROOT)
  769. FAR const char *devname = CONFIG_AUDIO_DEV_PATH;
  770. FAR const char *ptr;
  771. FAR char *pathptr;
  772. #endif
  773. /* Allocate the upper-half data structure */
  774. upper = (FAR struct audio_upperhalf_s *)kmm_zalloc(
  775. sizeof(struct audio_upperhalf_s));
  776. if (!upper)
  777. {
  778. auderr("ERROR: Allocation failed\n");
  779. return -ENOMEM;
  780. }
  781. /* Initialize the Audio device structure
  782. * (it was already zeroed by kmm_zalloc())
  783. */
  784. nxsem_init(&upper->exclsem, 0, 1);
  785. upper->dev = dev;
  786. #ifdef CONFIG_AUDIO_CUSTOM_DEV_PATH
  787. #ifdef CONFIG_AUDIO_DEV_ROOT
  788. /* This is the simple case ... No need to make a directory */
  789. strcpy(path, "/dev/");
  790. strcat(path, name);
  791. #else
  792. /* Ensure the path begins with "/dev" as we don't support placing device
  793. * anywhere but in the /dev directory
  794. */
  795. DEBUGASSERT(strncmp(devname, "/dev", 4) == 0);
  796. /* Create a /dev/audio directory. */
  797. if (!dev_audio_created)
  798. {
  799. /* Get path name after "/dev" */
  800. ptr = &devname[4];
  801. if (*ptr == '/')
  802. {
  803. ptr++;
  804. }
  805. strcpy(path, "/dev/");
  806. pathptr = &path[5];
  807. /* Do mkdir for each segment of the path */
  808. while (*ptr != '\0')
  809. {
  810. /* Build next path segment into path variable */
  811. while (*ptr != '/' && *ptr != '\0')
  812. {
  813. *pathptr++ = *ptr++;
  814. }
  815. *pathptr = '\0';
  816. /* Make this level of directory */
  817. mkdir(path, 0644);
  818. /* Check for another level */
  819. *pathptr++ = '/';
  820. if (*ptr == '/')
  821. {
  822. ptr++;
  823. }
  824. }
  825. /* Indicate we have created the audio dev path */
  826. dev_audio_created = true;
  827. }
  828. /* Now build the path for registration */
  829. strcpy(path, devname);
  830. if (devname[sizeof(devname)-1] != '/')
  831. {
  832. strcat(path, "/");
  833. }
  834. strcat(path, name);
  835. #endif /* CONFIG_AUDIO_DEV_PATH=="/dev" */
  836. #else /* CONFIG_AUDIO_CUSTOM_DEV_PATH */
  837. /* Create a /dev/audio directory. */
  838. if (!dev_audio_created)
  839. {
  840. /* We don't check for error here because even if it fails, then
  841. * the register_driver call below will return an error condition
  842. * for us.
  843. */
  844. mkdir(devname, 0644);
  845. dev_audio_created = true;
  846. }
  847. /* Register the Audio device */
  848. memset(path, 0, AUDIO_MAX_DEVICE_PATH);
  849. strcpy(path, devname);
  850. strcat(path, "/");
  851. strncat(path, name, AUDIO_MAX_DEVICE_PATH - 11);
  852. #endif
  853. /* Give the lower-half a context to the upper half */
  854. dev->upper = audio_callback;
  855. dev->priv = upper;
  856. audinfo("Registering %s\n", path);
  857. return register_driver(path, &g_audioops, 0666, upper);
  858. }
  859. #endif /* CONFIG_AUDIO */