blob: a8f5c1662a396754af5bae88633cecfaae0a4c40 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Audio output device.
5 */
6#include "Common.h"
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
Marco Nelissenbd642f32009-12-04 15:50:25 -080011#include <alsa/asoundlib.h>
The Android Open Source Project52d4c302009-03-03 19:29:09 -080012
13#include <fcntl.h>
14#include <sys/ioctl.h>
15#include <linux/input.h>
16
17
18/*
19 * Input event device state.
20 */
21typedef struct AudioState {
Marco Nelissenbd642f32009-12-04 15:50:25 -080022 snd_pcm_t *handle;
The Android Open Source Project52d4c302009-03-03 19:29:09 -080023} AudioState;
24
25/*
26 * Set some stuff up.
27 */
28static int configureInitialState(const char* pathName, AudioState* audioState)
29{
30#if BUILD_SIM_WITHOUT_AUDIO
31 return 0;
32#else
Marco Nelissenbd642f32009-12-04 15:50:25 -080033 audioState->handle = NULL;
The Android Open Source Project52d4c302009-03-03 19:29:09 -080034
Marco Nelissenbd642f32009-12-04 15:50:25 -080035 snd_pcm_open(&audioState->handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
The Android Open Source Project52d4c302009-03-03 19:29:09 -080036
Marco Nelissenbd642f32009-12-04 15:50:25 -080037 if (audioState->handle) {
38 snd_pcm_hw_params_t *params;
39 snd_pcm_hw_params_malloc(&params);
40 snd_pcm_hw_params_any(audioState->handle, params);
41 snd_pcm_hw_params_set_access(audioState->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
42 snd_pcm_hw_params_set_format(audioState->handle, params, SND_PCM_FORMAT_S16_LE);
43 unsigned int rate = 44100;
44 snd_pcm_hw_params_set_rate_near(audioState->handle, params, &rate, NULL);
45 snd_pcm_hw_params_set_channels(audioState->handle, params, 2);
46 snd_pcm_hw_params(audioState->handle, params);
47 snd_pcm_hw_params_free(params);
48 } else {
49 wsLog("Couldn't open audio hardware, faking it\n");
The Android Open Source Project52d4c302009-03-03 19:29:09 -080050 }
Marco Nelissenbd642f32009-12-04 15:50:25 -080051
The Android Open Source Project52d4c302009-03-03 19:29:09 -080052 return 0;
53#endif
54}
55
56/*
Marco Nelissenbd642f32009-12-04 15:50:25 -080057 * Write audio data.
The Android Open Source Project52d4c302009-03-03 19:29:09 -080058 */
59static ssize_t writeAudio(FakeDev* dev, int fd, const void* buf, size_t count)
60{
61#if BUILD_SIM_WITHOUT_AUDIO
62 return 0;
63#else
64 AudioState *state = (AudioState*)dev->state;
Marco Nelissenbd642f32009-12-04 15:50:25 -080065 if (state->handle != NULL) {
66 snd_pcm_writei(state->handle, buf, count / 4);
67 return count;
68 }
The Android Open Source Project52d4c302009-03-03 19:29:09 -080069
70 // fake timing
Marco Nelissenac2a5cf2009-12-04 14:44:43 -080071 usleep(count * 10000 / (441 * 4));
The Android Open Source Project52d4c302009-03-03 19:29:09 -080072 return count;
73#endif
74}
75
76/*
77 * Handle event ioctls.
78 */
79static int ioctlAudio(FakeDev* dev, int fd, int request, void* argp)
80{
81 return -1;
82}
83
84/*
85 * Free up our state before closing down the fake descriptor.
86 */
87static int closeAudio(FakeDev* dev, int fd)
88{
89#if BUILD_SIM_WITHOUT_AUDIO
90 return 0;
91#else
92 AudioState *state = (AudioState*)dev->state;
Marco Nelissenbd642f32009-12-04 15:50:25 -080093 snd_pcm_close(state->handle);
The Android Open Source Project52d4c302009-03-03 19:29:09 -080094 free(state);
95 dev->state = NULL;
96 return 0;
97#endif
98}
99
100/*
101 * Open an audio output device.
102 */
103FakeDev* wsOpenDevAudio(const char* pathName, int flags)
104{
105 FakeDev* newDev = wsCreateFakeDev(pathName);
106 if (newDev != NULL) {
107 newDev->write = writeAudio;
108 newDev->ioctl = ioctlAudio;
109 newDev->close = closeAudio;
110
111 AudioState* eventState = calloc(1, sizeof(AudioState));
112
113 if (configureInitialState(pathName, eventState) != 0) {
114 free(eventState);
115 return NULL;
116 }
117 newDev->state = eventState;
118 }
119
120 return newDev;
121}