/**************************************************************************** * apps/audioutils/nxaudio/nxaudio.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * name: configure_audio ****************************************************************************/ static int configure_audio(int fd, int ch, int fs, int bps, int chmap) { struct audio_caps_desc_s cap; cap.caps.ac_len = sizeof(struct audio_caps_s); cap.caps.ac_type = AUDIO_TYPE_OUTPUT; cap.caps.ac_channels = ch; cap.caps.ac_chmap = chmap; cap.caps.ac_controls.hw[0] = fs; cap.caps.ac_controls.b[2] = bps; cap.caps.ac_controls.b[3] = 0; /* Just set 0 */ return ioctl(fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap); } /**************************************************************************** * name: create_audiomq ****************************************************************************/ static mqd_t create_audiomq(int fd, int buf_num) { mqd_t ret; struct mq_attr attr; attr.mq_maxmsg = buf_num; attr.mq_msgsize = sizeof(struct audio_msg_s); attr.mq_curmsgs = 0; attr.mq_flags = 0; ret = mq_open(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME, O_RDWR | O_CREAT, 0644, &attr); if (ret >= (mqd_t)0) { int rr; if ((rr = ioctl(fd, AUDIOIOC_REGISTERMQ, (unsigned long)ret)) < 0) { printf("mq register failed: %d, %d\n", rr, errno); } } return ret; } /**************************************************************************** * name: create_audio_buffers ****************************************************************************/ static FAR struct ap_buffer_s **create_audio_buffers(int fd, int num, int sz) { int i; struct audio_buf_desc_s desc; FAR struct ap_buffer_s **ret; ret = (FAR struct ap_buffer_s **)calloc(num, sizeof(FAR void *)); for (i = 0; i < num; i++) { desc.numbytes = sz; desc.u.pbuffer = &ret[i]; ioctl(fd, AUDIOIOC_ALLOCBUFFER, (unsigned long)(uintptr_t)&desc); } return ret; } /**************************************************************************** * name: free_audio_buffers ****************************************************************************/ static void free_audio_buffers(FAR struct nxaudio_s *nxaudio) { int x; struct audio_buf_desc_s desc; for (x = 0; x < nxaudio->abufnum; x++) { if (nxaudio->abufs[x] != NULL) { desc.u.buffer = nxaudio->abufs[x]; ioctl(nxaudio->fd, AUDIOIOC_FREEBUFFER, (unsigned long)(uintptr_t)&desc); } } free(nxaudio->abufs); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * name: fin_nxaudio ****************************************************************************/ void fin_nxaudio(FAR struct nxaudio_s *nxaudio) { free_audio_buffers(nxaudio); ioctl(nxaudio->fd, AUDIOIOC_STOP, 0); ioctl(nxaudio->fd, AUDIOIOC_UNREGISTERMQ, (unsigned long)nxaudio->mq); ioctl(nxaudio->fd, AUDIOIOC_RELEASE, 0); ioctl(nxaudio->fd, AUDIOIOC_SHUTDOWN, 0); mq_close(nxaudio->mq); mq_unlink(CONFIG_AUDIOUTILS_NXAUDIO_MSGQNAME); close(nxaudio->fd); } /**************************************************************************** * name: init_nxaudio ****************************************************************************/ int init_nxaudio(FAR struct nxaudio_s *nxaudio, int fs, int bps, int chnum) { struct ap_buffer_info_s buf_info; nxaudio->fd = open(CONFIG_AUDIOUTILS_NXAUDIO_DEVPATH, O_RDWR | O_CLOEXEC); if (nxaudio->fd >= 0) { if (ioctl(nxaudio->fd, AUDIOIOC_RESERVE, 0) < 0) { close(nxaudio->fd); return -1; } /* Audio configuration: set channel num, FS and bps */ configure_audio(nxaudio->fd, chnum, fs, bps, 0); nxaudio->chnum = chnum; ioctl(nxaudio->fd, AUDIOIOC_GETBUFFERINFO, (unsigned long)(uintptr_t)&buf_info); /* Create message queue to communicate with audio driver */ nxaudio->mq = create_audiomq(nxaudio->fd, buf_info.nbuffers + 8); /* Create audio buffers to inject audio sample */ nxaudio->abufs = create_audio_buffers(nxaudio->fd, buf_info.nbuffers, buf_info.buffer_size); nxaudio->abufnum = buf_info.nbuffers; return 0; } else { return -1; } } /**************************************************************************** * name: nxaudio_enqbuffer ****************************************************************************/ int nxaudio_enqbuffer(FAR struct nxaudio_s *nxaudio, FAR struct ap_buffer_s *apb) { struct audio_buf_desc_s desc; desc.numbytes = apb->nbytes; desc.u.buffer = apb; return ioctl(nxaudio->fd, AUDIOIOC_ENQUEUEBUFFER, (unsigned long)(uintptr_t)&desc); } /**************************************************************************** * name: nxaudio_setvolume ****************************************************************************/ int nxaudio_setvolume(FAR struct nxaudio_s *nxaudio, uint16_t vol) { struct audio_caps_desc_s cap_desc; cap_desc.caps.ac_len = sizeof(struct audio_caps_s); cap_desc.caps.ac_type = AUDIO_TYPE_FEATURE; cap_desc.caps.ac_format.hw = AUDIO_FU_VOLUME; cap_desc.caps.ac_controls.hw[0] = vol; return ioctl(nxaudio->fd, AUDIOIOC_CONFIGURE, (unsigned long)(uintptr_t)&cap_desc); } /**************************************************************************** * name: nxaudio_start ****************************************************************************/ int nxaudio_start(FAR struct nxaudio_s *nxaudio) { return ioctl(nxaudio->fd, AUDIOIOC_START, 0); } /**************************************************************************** * name: nxaudio_start ****************************************************************************/ int nxaudio_stop(FAR struct nxaudio_s *nxaudio) { struct audio_msg_s term_msg; term_msg.msg_id = AUDIO_MSG_STOP; term_msg.u.data = 0; mq_send(nxaudio->mq, (FAR const char *)&term_msg, sizeof(term_msg), 0); return OK; } /**************************************************************************** * name: nxaudio_msgloop ****************************************************************************/ int nxaudio_msgloop(FAR struct nxaudio_s *nxaudio, FAR struct nxaudio_callbacks_s *cbs, unsigned long arg) { bool running = true; struct audio_msg_s msg; unsigned int prio; ssize_t size; if (!cbs) { return -1; } while (running) { size = mq_receive(nxaudio->mq, (FAR char *)&msg, sizeof(msg), &prio); if (size != sizeof(msg)) { continue; } switch (msg.msg_id) { case AUDIO_MSG_DEQUEUE: if (cbs->dequeue) { cbs->dequeue(arg, msg.u.ptr); } break; case AUDIO_MSG_COMPLETE: if (cbs->complete) { cbs->complete(arg); } break; case AUDIO_MSG_STOP: running = false; break; case AUDIO_MSG_USER: if (cbs->user) { cbs->user(arg, &msg, &running); } break; default: break; } } return 0; }