Initial revision 6759
[qball-mpd.git] / src / audioOutputs / .svn / text-base / audioOutput_mvp.c.svn-base
blobea365c6576f4890b924085c1686f6ad7b0af67e6
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  *
5  * Media MVP audio output based on code from MVPMC project:
6  * http://mvpmc.sourceforge.net/
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
22 #include "../audioOutput.h"
24 #include <stdlib.h>
26 #ifdef HAVE_MVP
28 #include "../conf.h"
29 #include "../log.h"
31 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
40 typedef struct {
41         unsigned long dsp_status;
42         unsigned long stream_decode_type;
43         unsigned long sample_rate;
44         unsigned long bit_rate;
45         unsigned long raw[64 / sizeof(unsigned long)];
46 } aud_status_t;
48 #define MVP_SET_AUD_STOP                _IOW('a',1,int)
49 #define MVP_SET_AUD_PLAY                _IOW('a',2,int)
50 #define MVP_SET_AUD_PAUSE       _IOW('a',3,int)
51 #define MVP_SET_AUD_UNPAUSE     _IOW('a',4,int)
52 #define MVP_SET_AUD_SRC         _IOW('a',5,int)
53 #define MVP_SET_AUD_MUTE                _IOW('a',6,int)
54 #define MVP_SET_AUD_BYPASS      _IOW('a',8,int)
55 #define MVP_SET_AUD_CHANNEL     _IOW('a',9,int)
56 #define MVP_GET_AUD_STATUS      _IOR('a',10,aud_status_t)
57 #define MVP_SET_AUD_VOLUME      _IOW('a',13,int)
58 #define MVP_GET_AUD_VOLUME      _IOR('a',14,int)
59 #define MVP_SET_AUD_STREAMTYPE  _IOW('a',15,int)
60 #define MVP_SET_AUD_FORMAT      _IOW('a',16,int)
61 #define MVP_GET_AUD_SYNC                _IOR('a',21,pts_sync_data_t*)
62 #define MVP_SET_AUD_STC         _IOW('a',22,long long int *)
63 #define MVP_SET_AUD_SYNC                _IOW('a',23,int)
64 #define MVP_SET_AUD_END_STREAM  _IOW('a',25,int)
65 #define MVP_SET_AUD_RESET       _IOW('a',26,int)
66 #define MVP_SET_AUD_DAC_CLK     _IOW('a',27,int)
67 #define MVP_GET_AUD_REGS                _IOW('a',28,aud_ctl_regs_t*)
69 typedef struct _MvpData {
70         int fd;
71 } MvpData;
73 static int pcmfrequencies[][3] = {
74         {9, 8000, 32000},
75         {10, 11025, 44100},
76         {11, 12000, 48000},
77         {1, 16000, 32000},
78         {2, 22050, 44100},
79         {3, 24000, 48000},
80         {5, 32000, 32000},
81         {0, 44100, 44100},
82         {7, 48000, 48000},
83         {13, 64000, 32000},
84         {14, 88200, 44100},
85         {15, 96000, 48000}
88 static int numfrequencies = sizeof(pcmfrequencies) / 12;
90 static int mvp_testDefault(void)
92         int fd;
94         fd = open("/dev/adec_pcm", O_WRONLY);
96         if (fd) {
97                 close(fd);
98                 return 0;
99         }
101         WARNING("Error opening PCM device \"/dev/adec_pcm\": %s\n",
102                 strerror(errno));
104         return -1;
107 static int mvp_initDriver(AudioOutput * audioOutput, ConfigParam * param)
109         MvpData *md = xmalloc(sizeof(MvpData));
110         md->fd = -1;
111         audioOutput->data = md;
113         return 0;
116 static void mvp_finishDriver(AudioOutput * audioOutput)
118         MvpData *md = audioOutput->data;
119         free(md);
122 static int mvp_setPcmParams(MvpData * md, unsigned long rate, int channels,
123                             int big_endian, int bits)
125         int iloop;
126         int mix[5];
128         if (channels == 1)
129                 mix[0] = 1;
130         else if (channels == 2)
131                 mix[0] = 0;
132         else
133                 return -1;
135         /* 0,1=24bit(24) , 2,3=16bit */
136         if (bits == 16)
137                 mix[1] = 2;
138         else if (bits == 24)
139                 mix[1] = 0;
140         else
141                 return -1;
143         mix[3] = 0;     /* stream type? */
145         if (big_endian == 1)
146                 mix[4] = 1;
147         else if (big_endian == 0)
148                 mix[4] = 0;
149         else
150                 return -1;
152         /*
153          * if there is an exact match for the frequency, use it.
154          */
155         for (iloop = 0; iloop < numfrequencies; iloop++) {
156                 if (rate == pcmfrequencies[iloop][1]) {
157                         mix[2] = pcmfrequencies[iloop][0];
158                         break;
159                 }
160         }
162         if (iloop >= numfrequencies) {
163                 ERROR("Can not find suitable output frequency for %ld\n", rate);
164                 return -1;
165         }
167         if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
168                 ERROR("Can not set audio format\n");
169                 return -1;
170         }
172         if (ioctl(md->fd, MVP_SET_AUD_SYNC, 2) != 0) {
173                 ERROR("Can not set audio sync\n");
174                 return -1;
175         }
177         if (ioctl(md->fd, MVP_SET_AUD_PLAY, 0) < 0) {
178                 ERROR("Can not set audio play mode\n");
179                 return -1;
180         }
182         return 0;
185 static int mvp_openDevice(AudioOutput * audioOutput)
187         long long int stc = 0;
188         MvpData *md = audioOutput->data;
189         AudioFormat *audioFormat = &audioOutput->outAudioFormat;
190         int mix[5] = { 0, 2, 7, 1, 0 };
192         if ((md->fd = open("/dev/adec_pcm", O_RDWR | O_NONBLOCK)) < 0) {
193                 ERROR("Error opening /dev/adec_pcm: %s\n", strerror(errno));
194                 return -1;
195         }
196         if (ioctl(md->fd, MVP_SET_AUD_SRC, 1) < 0) {
197                 ERROR("Error setting audio source: %s\n", strerror(errno));
198                 return -1;
199         }
200         if (ioctl(md->fd, MVP_SET_AUD_STREAMTYPE, 0) < 0) {
201                 ERROR("Error setting audio streamtype: %s\n", strerror(errno));
202                 return -1;
203         }
204         if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
205                 ERROR("Error setting audio format: %s\n", strerror(errno));
206                 return -1;
207         }
208         ioctl(md->fd, MVP_SET_AUD_STC, &stc);
209         if (ioctl(md->fd, MVP_SET_AUD_BYPASS, 1) < 0) {
210                 ERROR("Error setting audio streamtype: %s\n", strerror(errno));
211                 return -1;
212         }
213 #ifdef WORDS_BIGENDIAN
214         mvp_setPcmParams(md, audioFormat->sampleRate, audioFormat->channels, 0,
215                          audioFormat->bits);
216 #else
217         mvp_setPcmParams(md, audioFormat->sampleRate, audioFormat->channels, 1,
218                          audioFormat->bits);
219 #endif
220         audioOutput->open = 1;
221         return 0;
224 static void mvp_closeDevice(AudioOutput * audioOutput)
226         MvpData *md = audioOutput->data;
227         if (md->fd >= 0)
228                 close(md->fd);
229         md->fd = -1;
230         audioOutput->open = 0;
233 static void mvp_dropBufferedAudio(AudioOutput * audioOutput)
235         MvpData *md = audioOutput->data;
236         if (md->fd >= 0) {
237                 ioctl(md->fd, MVP_SET_AUD_RESET, 0x11);
238                 close(md->fd);
239                 md->fd = -1;
240                 audioOutput->open = 0;
241         }
244 static int mvp_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
246         MvpData *md = audioOutput->data;
247         int ret;
249         /* reopen the device since it was closed by dropBufferedAudio */
250         if (md->fd < 0)
251                 mvp_openDevice(audioOutput);
253         while (size > 0) {
254                 ret = write(md->fd, playChunk, size);
255                 if (ret < 0) {
256                         if (errno == EINTR)
257                                 continue;
258                         ERROR("closing mvp PCM device due to write error: "
259                               "%s\n", strerror(errno));
260                         mvp_closeDevice(audioOutput);
261                         return -1;
262                 }
263                 playChunk += ret;
264                 size -= ret;
265         }
266         return 0;
269 AudioOutputPlugin mvpPlugin = {
270         "mvp",
271         mvp_testDefault,
272         mvp_initDriver,
273         mvp_finishDriver,
274         mvp_openDevice,
275         mvp_playAudio,
276         mvp_dropBufferedAudio,
277         mvp_closeDevice,
278         NULL,   /* sendMetadataFunc */
281 #else /* HAVE_MVP */
283 DISABLED_AUDIO_OUTPUT_PLUGIN(mvpPlugin)
284 #endif /* HAVE_MVP */