1/* 2 * Copyright (C) 2010 Julien BLACHE <jb@jblache.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <string.h> 27#include <errno.h> 28#include <stdint.h> 29#include <inttypes.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <sys/ioctl.h> 34 35#include <soundcard.h> 36 37#include "conffile.h" 38#include "logger.h" 39#include "player.h" 40#include "laudio.h" 41 42 43struct pcm_packet 44{ 45 uint8_t samples[STOB(AIRTUNES_V2_PACKET_SAMPLES)]; 46 47 uint64_t rtptime; 48 49 size_t offset; 50 51 struct pcm_packet *next; 52}; 53 54static uint64_t pcm_pos; 55static uint64_t pcm_start_pos; 56static int pcm_buf_threshold; 57static int pcm_retry; 58 59static struct pcm_packet *pcm_pkt_head; 60static struct pcm_packet *pcm_pkt_tail; 61 62static char *card_name; 63static int oss_fd; 64 65static enum laudio_state pcm_status; 66static laudio_status_cb status_cb; 67 68 69static void 70update_status(enum laudio_state status) 71{ 72 pcm_status = status; 73 status_cb(status); 74} 75 76void 77laudio_write(uint8_t *buf, uint64_t rtptime) 78{ 79 struct pcm_packet *pkt; 80 int scratch; 81 int nsamp; 82 int ret; 83 84 pkt = (struct pcm_packet *)malloc(sizeof(struct pcm_packet)); 85 if (!pkt) 86 { 87 DPRINTF(E_LOG, L_LAUDIO, "Out of memory for PCM pkt\n"); 88 89 update_status(LAUDIO_FAILED); 90 return; 91 } 92 93 memcpy(pkt->samples, buf, sizeof(pkt->samples)); 94 95 pkt->rtptime = rtptime; 96 pkt->offset = 0; 97 pkt->next = NULL; 98 99 if (pcm_pkt_tail) 100 { 101 pcm_pkt_tail->next = pkt; 102 pcm_pkt_tail = pkt; 103 } 104 else 105 { 106 pcm_pkt_head = pkt; 107 pcm_pkt_tail = pkt; 108 } 109 110 if (pcm_pos < pcm_pkt_head->rtptime) 111 { 112 pcm_pos += AIRTUNES_V2_PACKET_SAMPLES; 113 114 return; 115 } 116 else if ((pcm_status != LAUDIO_RUNNING) && (pcm_pos >= pcm_start_pos)) 117 { 118 /* Start audio output */ 119 scratch = PCM_ENABLE_OUTPUT; 120 ret = ioctl(oss_fd, SNDCTL_DSP_SETTRIGGER, &scratch); 121 if (ret < 0) 122 { 123 DPRINTF(E_LOG, L_LAUDIO, "Could not enable output: %s\n", strerror(errno)); 124 125 update_status(LAUDIO_FAILED); 126 return; 127 } 128 129 update_status(LAUDIO_RUNNING); 130 } 131 132 pkt = pcm_pkt_head; 133 134 while (pkt) 135 { 136 nsamp = write(oss_fd, pkt->samples + pkt->offset, sizeof(pkt->samples) - pkt->offset); 137 if (nsamp < 0) 138 { 139 if (errno == EAGAIN) 140 { 141 pcm_retry++; 142 143 if (pcm_retry < 10) 144 return; 145 } 146 147 DPRINTF(E_LOG, L_LAUDIO, "Write error: %s\n", strerror(errno)); 148 149 update_status(LAUDIO_FAILED); 150 return; 151 } 152 153 pcm_retry = 0; 154 155 pkt->offset += nsamp; 156 157 nsamp = BTOS(nsamp); 158 pcm_pos += nsamp; 159 160 if (pkt->offset == sizeof(pkt->samples)) 161 { 162 pcm_pkt_head = pkt->next; 163 164 if (pkt == pcm_pkt_tail) 165 pcm_pkt_tail = NULL; 166 167 free(pkt); 168 169 pkt = pcm_pkt_head; 170 } 171 172 /* Don't let the buffer fill up too much */ 173 if (nsamp == AIRTUNES_V2_PACKET_SAMPLES) 174 break; 175 } 176} 177 178uint64_t 179laudio_get_pos(void) 180{ 181 int delay; 182 int ret; 183 184 ret = ioctl(oss_fd, SNDCTL_DSP_GETODELAY, &delay); 185 if (ret < 0) 186 { 187 DPRINTF(E_LOG, L_LAUDIO, "Could not obtain output delay: %s\n", strerror(errno)); 188 189 return pcm_pos; 190 } 191 192 return pcm_pos - BTOS(delay); 193} 194 195void 196laudio_set_volume(int vol) 197{ 198 int oss_vol; 199 int ret; 200 201 vol = vol & 0xff; 202 oss_vol = vol | (vol << 8); 203 204 ret = ioctl(oss_fd, SNDCTL_DSP_SETPLAYVOL, &oss_vol); 205 if (ret < 0) 206 { 207 DPRINTF(E_LOG, L_LAUDIO, "Could not set volume: %s\n", strerror(errno)); 208 209 return; 210 } 211 212 DPRINTF(E_DBG, L_LAUDIO, "Setting PCM volume to %d (real: %d)\n", vol, (oss_vol & 0xff)); 213} 214 215int 216laudio_start(uint64_t cur_pos, uint64_t next_pkt) 217{ 218 int scratch; 219 int ret; 220 221 DPRINTF(E_DBG, L_LAUDIO, "PCM will start after %d samples (%d packets)\n", pcm_buf_threshold, pcm_buf_threshold / AIRTUNES_V2_PACKET_SAMPLES); 222 223 /* Make pcm_pos the rtptime of the packet containing cur_pos */ 224 pcm_pos = next_pkt; 225 while (pcm_pos > cur_pos) 226 pcm_pos -= AIRTUNES_V2_PACKET_SAMPLES; 227 228 pcm_start_pos = next_pkt + pcm_buf_threshold; 229 230 /* FIXME check for OSS - Compensate threshold, as it's taken into account by snd_pcm_delay() */ 231 pcm_pos += pcm_buf_threshold; 232 233 DPRINTF(E_DBG, L_LAUDIO, "PCM pos %" PRIu64 ", start pos %" PRIu64 "\n", pcm_pos, pcm_start_pos); 234 235 pcm_pkt_head = NULL; 236 pcm_pkt_tail = NULL; 237 238 pcm_retry = 0; 239 240 scratch = 0; 241 ret = ioctl(oss_fd, SNDCTL_DSP_SETTRIGGER, &scratch); 242 if (ret < 0) 243 { 244 DPRINTF(E_LOG, L_LAUDIO, "Could not set trigger: %s\n", strerror(errno)); 245 246 return -1; 247 } 248 249 update_status(LAUDIO_STARTED); 250 251 return 0; 252} 253 254void 255laudio_stop(void) 256{ 257 struct pcm_packet *pkt; 258 int ret; 259 260 update_status(LAUDIO_STOPPING); 261 262 ret = ioctl(oss_fd, SNDCTL_DSP_HALT_OUTPUT, NULL); 263 if (ret < 0) 264 DPRINTF(E_LOG, L_LAUDIO, "Failed to halt output: %s\n", strerror(errno)); 265 266 for (pkt = pcm_pkt_head; pcm_pkt_head; pkt = pcm_pkt_head) 267 { 268 pcm_pkt_head = pkt->next; 269 270 free(pkt); 271 } 272 273 pcm_pkt_head = NULL; 274 pcm_pkt_tail = NULL; 275 276 update_status(LAUDIO_OPEN); 277} 278 279int 280laudio_open(void) 281{ 282 audio_buf_info bi; 283 int scratch; 284 int ret; 285 286 oss_fd = open(card_name, O_RDWR | O_NONBLOCK); 287 if (oss_fd < 0) 288 { 289 DPRINTF(E_LOG, L_LAUDIO, "Could not open sound device: %s\n", strerror(errno)); 290 291 return -1; 292 } 293 294 scratch = 0; 295 ret = ioctl(oss_fd, SNDCTL_DSP_SETTRIGGER, &scratch); 296 if (ret < 0) 297 { 298 DPRINTF(E_LOG, L_LAUDIO, "Could not set trigger: %s\n", strerror(errno)); 299 300 goto out_fail; 301 } 302 303 scratch = AFMT_S16_LE; 304 errno = 0; 305 ret = ioctl(oss_fd, SNDCTL_DSP_SETFMT, &scratch); 306 if ((ret < 0) || (scratch != AFMT_S16_LE)) 307 { 308 if (errno) 309 DPRINTF(E_LOG, L_LAUDIO, "Could not set sample format (S16 LE): %s\n", strerror(errno)); 310 else 311 DPRINTF(E_LOG, L_LAUDIO, "Sample format S16 LE not supported\n"); 312 313 goto out_fail; 314 } 315 316 scratch = 2; 317 errno = 0; 318 ret = ioctl(oss_fd, SNDCTL_DSP_CHANNELS, &scratch); 319 if ((ret < 0) || (scratch != 2)) 320 { 321 if (errno) 322 DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo: %s\n", strerror(errno)); 323 else 324 DPRINTF(E_LOG, L_LAUDIO, "Stereo not supported\n"); 325 326 goto out_fail; 327 } 328 329 scratch = 44100; 330 errno = 0; 331 ret = ioctl(oss_fd, SNDCTL_DSP_SPEED, &scratch); 332 if ((ret < 0) || (scratch != 44100)) 333 { 334 if (errno) 335 DPRINTF(E_LOG, L_LAUDIO, "Could not set speed (44100): %s\n", strerror(errno)); 336 else 337 DPRINTF(E_LOG, L_LAUDIO, "Sample rate 44100 not supported\n"); 338 339 goto out_fail; 340 } 341 342 ret = ioctl(oss_fd, SNDCTL_DSP_GETOSPACE, &bi); 343 if (ret < 0) 344 { 345 DPRINTF(E_LOG, L_LAUDIO, "Couldn't get output buffer status: %s\n", strerror(errno)); 346 347 goto out_fail; 348 } 349 350 pcm_buf_threshold = (BTOS(bi.bytes) / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; 351 352 update_status(LAUDIO_OPEN); 353 354 return 0; 355 356 out_fail: 357 close(oss_fd); 358 oss_fd = -1; 359 360 return -1; 361} 362 363void 364laudio_close(void) 365{ 366 struct pcm_packet *pkt; 367 int ret; 368 369 ret = ioctl(oss_fd, SNDCTL_DSP_HALT_OUTPUT, NULL); 370 if (ret < 0) 371 DPRINTF(E_LOG, L_LAUDIO, "Failed to halt output: %s\n", strerror(errno)); 372 373 close(oss_fd); 374 oss_fd = -1; 375 376 for (pkt = pcm_pkt_head; pcm_pkt_head; pkt = pcm_pkt_head) 377 { 378 pcm_pkt_head = pkt->next; 379 380 free(pkt); 381 } 382 383 pcm_pkt_head = NULL; 384 pcm_pkt_tail = NULL; 385 386 update_status(LAUDIO_CLOSED); 387} 388 389 390int 391laudio_init(laudio_status_cb cb) 392{ 393 oss_sysinfo si; 394 int ret; 395 396 status_cb = cb; 397 pcm_status = LAUDIO_CLOSED; 398 399 card_name = cfg_getstr(cfg_getsec(cfg, "audio"), "card"); 400 401 oss_fd = open(card_name, O_RDWR); 402 if (oss_fd < 0) 403 { 404 DPRINTF(E_FATAL, L_LAUDIO, "Could not open sound device: %s\n", strerror(errno)); 405 406 return -1; 407 } 408 409 ret = ioctl(oss_fd, SNDCTL_SYSINFO, &si); 410 411 close(oss_fd); 412 oss_fd = -1; 413 414 if (ret < 0) 415 { 416 DPRINTF(E_FATAL, L_LAUDIO, "Could not check OSS version: %s\n", strerror(errno)); 417 418 return -1; 419 } 420 421 if (si.versionnum < 0x040000) 422 { 423 DPRINTF(E_FATAL, L_LAUDIO, "Your OSS version (%s) is too old; version 4.0.0+ is required\n", si.version); 424 425 return -1; 426 } 427 428 return 0; 429} 430 431void 432laudio_deinit(void) 433{ 434 /* EMPTY */ 435} 436