version 1.4, 2008/06/03 14:36:20 |
version 1.5, 2008/08/14 09:58:55 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
|
|
|
#include <sys/types.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/audioio.h> |
|
|
#include <err.h> |
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
#include "conf.h" |
#include "conf.h" |
|
|
#include "dev.h" |
#include "dev.h" |
|
|
/* |
/* |
* convert sun device parameters to struct params |
* Convert sun device parameters to struct aparams |
*/ |
*/ |
int |
int |
sun_infotopar(struct audio_prinfo *ai, struct aparams *par) |
sun_infotopar(struct audio_prinfo *ai, struct aparams *par) |
|
|
} |
} |
|
|
/* |
/* |
* Convert struct params to sun device parameters. |
* Convert struct aparams to sun device parameters. |
*/ |
*/ |
void |
void |
sun_partoinfo(struct audio_prinfo *ai, struct aparams *par) |
sun_partoinfo(struct audio_prinfo *ai, struct aparams *par) |
|
|
* Open the device and pause it, so later play and record |
* Open the device and pause it, so later play and record |
* can be started simultaneously. |
* can be started simultaneously. |
* |
* |
* int "infr" and "onfd" we return the input and the output |
* in "infr" and "onfd" we return the input and the output |
* block sizes respectively. |
* block sizes respectively. |
*/ |
*/ |
int |
int |
dev_init(char *path, struct aparams *ipar, struct aparams *opar, |
sun_open(char *path, struct aparams *ipar, struct aparams *opar, |
unsigned *infr, unsigned *onfr) |
unsigned *infr, unsigned *onfr) |
{ |
{ |
int fd; |
int fd; |
|
|
return -1; |
return -1; |
} |
} |
if (ioctl(fd, AUDIO_GETINFO, &aui) < 0) { |
if (ioctl(fd, AUDIO_GETINFO, &aui) < 0) { |
warn("dev_init: getinfo"); |
warn("sun_open: getinfo"); |
close(fd); |
close(fd); |
return -1; |
return -1; |
} |
} |
|
|
return fd; |
return fd; |
} |
} |
|
|
|
/* |
|
* Drain and close the device |
|
*/ |
void |
void |
dev_done(int fd) |
sun_close(int fd) |
{ |
{ |
close(fd); |
close(fd); |
DPRINTF("dev_done: closed\n"); |
DPRINTF("sun_close: closed\n"); |
} |
} |
|
|
/* |
/* |
* Start play/record. |
* Start play/record simultaneously. Play buffers must be filled. |
*/ |
*/ |
void |
void |
dev_start(int fd) |
sun_start(int fd) |
{ |
{ |
audio_info_t aui; |
audio_info_t aui; |
|
|
|
|
AUDIO_INITINFO(&aui); |
AUDIO_INITINFO(&aui); |
aui.play.pause = aui.record.pause = 0; |
aui.play.pause = aui.record.pause = 0; |
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) |
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) |
err(1, "dev_start: setinfo"); |
err(1, "sun_start: setinfo"); |
|
|
DPRINTF("dev_start: play/rec started\n"); |
DPRINTF("sun_start: play/rec started\n"); |
} |
} |
|
|
/* |
/* |
* Stop play/record and clear kernel buffers so that dev_start() can be called |
* Drain play buffers and then stop play/record simultaneously. |
* again. |
|
*/ |
*/ |
void |
void |
dev_stop(int fd) |
sun_stop(int fd) |
{ |
{ |
audio_info_t aui; |
audio_info_t aui; |
unsigned mode; |
|
|
|
if (ioctl(fd, AUDIO_DRAIN) < 0) |
|
err(1, "dev_stop: drain"); |
|
|
|
/* |
/* |
* The only way to clear kernel buffers and to pause the device |
* Sun API doesn't not allows us to drain and stop without |
* simultaneously is to set the mode again (to the same value). |
* loosing the sync between playback and record. So, for now we |
|
* just pause the device until this problem is worked around. |
|
* |
|
* there are three possible workarounds: |
|
* |
|
* 1) stop depending on this, ie. make the rest of the code |
|
* able to resynchronize playback to record. Then just |
|
* close/reset the device to stop it. |
|
* |
|
* 2) send "hiwat" blocks of silence and schedule the |
|
* very same amount of silence to drop. |
|
* |
|
* 3) modify the AUDIO_DRAIN ioctl(2) not to loose sync |
|
* |
*/ |
*/ |
if (ioctl(fd, AUDIO_GETINFO, &aui) < 0) |
|
err(1, "dev_stop: getinfo"); |
|
|
|
mode = aui.mode; |
|
AUDIO_INITINFO(&aui); |
AUDIO_INITINFO(&aui); |
aui.mode = mode; |
|
aui.play.pause = aui.record.pause = 1; |
aui.play.pause = aui.record.pause = 1; |
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) |
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) |
err(1, "dev_stop: setinfo"); |
err(1, "sun_stop: setinfo"); |
|
|
DPRINTF("dev_stop: play/rec stopped\n"); |
DPRINTF("sun_stop: play/rec stopped\n"); |
} |
} |
|
|
|
struct devops devops_sun = { |
|
sun_open, |
|
sun_close, |
|
sun_start, |
|
sun_stop |
|
}; |