aboutsummaryrefslogtreecommitdiffstats
path: root/hw/goldfish_audio.c
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
committerDavid 'Digit' Turner <digit@google.com>2009-09-14 14:32:27 -0700
commit5d8f37ad78fc66901af50c762029a501561f3b23 (patch)
tree206790f8f21000850a98c4f9590a79e779106278 /hw/goldfish_audio.c
parentcd059b15f2c7df69f4a087bd66900eb172e41d1c (diff)
downloadexternal_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.zip
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.gz
external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.bz2
Merge upstream QEMU 10.0.50 into the Android source tree.
This change integrates many changes from the upstream QEMU sources. Its main purpose is to enable correct ARMv6 and ARMv7 support to the Android emulator. Due to the nature of the upstream code base, this unfortunately also required changes to many other parts of the source. Note that to ensure easier integrations in the future, some source files and directories that have heavy Android-specific customization have been renamed with an -android suffix. The original files are still there for easier integration tracking, but *never* compiled. For example: net.c net-android.c qemu-char.c qemu-char-android.c slirp/ slirp-android/ etc... Tested on linux-x86, darwin-x86 and windows host machines.
Diffstat (limited to 'hw/goldfish_audio.c')
-rw-r--r--hw/goldfish_audio.c268
1 files changed, 181 insertions, 87 deletions
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
index d0a44b5..c8a6712 100644
--- a/hw/goldfish_audio.c
+++ b/hw/goldfish_audio.c
@@ -62,21 +62,25 @@ enum {
AUDIO_INT_READ_BUFFER_FULL = 1U << 2,
};
+struct goldfish_audio_buff {
+ uint32_t address;
+ uint32_t length;
+ uint8* data;
+ uint32_t capacity;
+ uint32_t offset;
+};
+
struct goldfish_audio_state {
struct goldfish_device dev;
- // pointers to our two write buffers
- uint32_t buffer_1, buffer_2;
- uint32_t read_buffer;
// buffer flags
uint32_t int_status;
// irq enable mask for int_status
uint32_t int_enable;
-#if USE_QEMU_AUDIO_IN
- uint32_t read_pos;
- uint32_t read_size;
-#else
+#ifndef USE_QEMU_AUDIO_IN
+ // address of the read buffer
+ uint32_t read_buffer;
// path to file or device to use for input
const char* input_source;
// true if input is a wav file
@@ -94,11 +98,9 @@ struct goldfish_audio_state {
int current_buffer;
// current data to write
- uint8* data_1;
- uint32_t data_1_length;
- uint8* data_2;
- uint32_t data_2_length;
-
+ struct goldfish_audio_buff out_buff1[1];
+ struct goldfish_audio_buff out_buff2[1];
+ struct goldfish_audio_buff in_buff[1];
// for QEMU sound output
QEMUSoundCard card;
@@ -108,24 +110,132 @@ struct goldfish_audio_state {
#endif
};
+static void
+goldfish_audio_buff_init( struct goldfish_audio_buff* b )
+{
+ b->address = 0;
+ b->length = 0;
+ b->data = NULL;
+ b->capacity = 0;
+ b->offset = 0;
+}
+
+static void
+goldfish_audio_buff_reset( struct goldfish_audio_buff* b )
+{
+ b->offset = 0;
+ b->length = 0;
+}
+
+static uint32_t
+goldfish_audio_buff_length( struct goldfish_audio_buff* b )
+{
+ return b->length;
+}
+
+static void
+goldfish_audio_buff_ensure( struct goldfish_audio_buff* b, uint32_t size )
+{
+ if (b->capacity < size) {
+ b->data = qemu_realloc(b->data, size);
+ b->capacity = size;
+ }
+}
+
+static void
+goldfish_audio_buff_set_address( struct goldfish_audio_buff* b, uint32_t addr )
+{
+ b->address = addr;
+}
+
+static void
+goldfish_audio_buff_set_length( struct goldfish_audio_buff* b, uint32_t len )
+{
+ b->length = len;
+ b->offset = 0;
+ goldfish_audio_buff_ensure(b, len);
+}
+
+static void
+goldfish_audio_buff_read( struct goldfish_audio_buff* b )
+{
+ cpu_physical_memory_read(b->address, b->data, b->length);
+}
+
+static void
+goldfish_audio_buff_write( struct goldfish_audio_buff* b )
+{
+ cpu_physical_memory_write(b->address, b->data, b->length);
+}
+
+static int
+goldfish_audio_buff_send( struct goldfish_audio_buff* b, int free, struct goldfish_audio_state* s )
+{
+ int ret, write = b->length;
+
+ if (write > free)
+ write = free;
+
+ ret = AUD_write(s->voice, b->data + b->offset, write);
+ b->offset += ret;
+ b->length -= ret;
+ return ret;
+}
+
+static int
+goldfish_audio_buff_available( struct goldfish_audio_buff* b )
+{
+ return b->length - b->offset;
+}
+
+static int
+goldfish_audio_buff_recv( struct goldfish_audio_buff* b, int avail, struct goldfish_audio_state* s )
+{
+ int missing = b->length - b->offset;
+ int avail2 = (avail > missing) ? missing : avail;
+ int read;
+
+ read = AUD_read(s->voicein, b->data + b->offset, avail2 );
+ if (read == 0)
+ return 0;
+
+ if (avail2 > 0)
+ D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read);
+
+ cpu_physical_memory_write( b->address + b->offset, b->data, read );
+ b->offset += read;
+
+ return read;
+}
+
+static void
+goldfish_audio_buff_put( struct goldfish_audio_buff* b, QEMUFile* f )
+{
+ qemu_put_be32(f, b->address );
+ qemu_put_be32(f, b->length );
+ qemu_put_be32(f, b->offset );
+ qemu_put_buffer(f, b->data, b->length );
+}
+
+static int
+goldfish_audio_buff_get( struct goldfish_audio_buff* b, QEMUFile* f )
+{
+ b->address = qemu_get_be32(f);
+ b->length = qemu_get_be32(f);
+ b->offset = qemu_get_be32(f);
+ goldfish_audio_buff_ensure(b, b->length);
+ qemu_get_buffer(f, b->data, b->length);
+}
+
/* update this whenever you change the goldfish_audio_state structure */
-#define AUDIO_STATE_SAVE_VERSION 1
+#define AUDIO_STATE_SAVE_VERSION 2
#define QFIELD_STRUCT struct goldfish_audio_state
QFIELD_BEGIN(audio_state_fields)
- QFIELD_INT32(buffer_1),
- QFIELD_INT32(buffer_2),
- QFIELD_INT32(read_buffer),
QFIELD_INT32(int_status),
QFIELD_INT32(int_enable),
-#if USE_QEMU_AUDIO_IN
- QFIELD_INT32(read_pos),
- QFIELD_INT32(read_size),
-#endif
QFIELD_INT32(read_buffer_available),
QFIELD_INT32(current_buffer),
- QFIELD_INT32(data_1_length),
- QFIELD_INT32(data_2_length),
QFIELD_END
static void audio_state_save( QEMUFile* f, void* opaque )
@@ -134,9 +244,9 @@ static void audio_state_save( QEMUFile* f, void* opaque )
qemu_put_struct(f, audio_state_fields, s);
- /* we can't write data_1 and data_2 directly */
- qemu_put_be32( f, s->data_1 - phys_ram_base );
- qemu_put_be32( f, s->data_2 - phys_ram_base );
+ goldfish_audio_buff_put (s->out_buff1, f);
+ goldfish_audio_buff_put (s->out_buff2, f);
+ goldfish_audio_buff_put (s->in_buff, f);
}
static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
@@ -149,8 +259,9 @@ static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
ret = qemu_get_struct(f, audio_state_fields, s);
if (!ret) {
- s->data_1 = qemu_get_be32(f) + phys_ram_base;
- s->data_2 = qemu_get_be32(f) + phys_ram_base;
+ goldfish_audio_buff_get( s->out_buff1, f );
+ goldfish_audio_buff_get( s->out_buff2, f );
+ goldfish_audio_buff_get (s->in_buff, f);
}
return -1;
}
@@ -158,25 +269,25 @@ static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
static void enable_audio(struct goldfish_audio_state *s, int enable)
{
// enable or disable the output voice
- if (s->voice != NULL)
+ if (s->voice != NULL) {
AUD_set_active_out(s->voice, (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0);
+ goldfish_audio_buff_reset( s->out_buff1 );
+ goldfish_audio_buff_reset( s->out_buff2 );
+ }
- if (s->voicein)
+ if (s->voicein) {
AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0);
- // reset buffer information
- s->data_1_length = 0;
- s->data_2_length = 0;
+ goldfish_audio_buff_reset( s->in_buff );
+ }
s->current_buffer = 0;
- s->read_pos = 0;
}
#if USE_QEMU_AUDIO_IN
static void start_read(struct goldfish_audio_state *s, uint32_t count)
{
//printf( "... goldfish audio start_read, count=%d\n", count );
- s->read_size = count;
- s->read_buffer_available = 0;
- s->read_pos = 0;
+ goldfish_audio_buff_set_length( s->in_buff, count );
+ s->read_buffer_available = count;
}
#else
static void start_read(struct goldfish_audio_state *s, uint32_t count)
@@ -255,7 +366,6 @@ static uint32_t goldfish_audio_read(void *opaque, target_phys_addr_t offset)
{
uint32_t ret;
struct goldfish_audio_state *s = opaque;
- offset -= s->dev.base;
switch(offset) {
case AUDIO_INT_STATUS:
// return current buffer status flags
@@ -277,6 +387,7 @@ static uint32_t goldfish_audio_read(void *opaque, target_phys_addr_t offset)
case AUDIO_READ_BUFFER_AVAILABLE:
D("%s: AUDIO_READ_BUFFER_AVAILABLE returns %d", __FUNCTION__,
s->read_buffer_available);
+ goldfish_audio_buff_write( s->in_buff );
return s->read_buffer_available;
default:
@@ -288,7 +399,6 @@ static uint32_t goldfish_audio_read(void *opaque, target_phys_addr_t offset)
static void goldfish_audio_write(void *opaque, target_phys_addr_t offset, uint32_t val)
{
struct goldfish_audio_state *s = opaque;
- offset -= s->dev.base;
switch(offset) {
case AUDIO_INT_ENABLE:
@@ -301,30 +411,34 @@ static void goldfish_audio_write(void *opaque, target_phys_addr_t offset, uint32
break;
case AUDIO_SET_WRITE_BUFFER_1:
/* save pointer to buffer 1 */
- s->buffer_1 = val;
+ D( "%s: AUDIO_SET_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
+ goldfish_audio_buff_set_address( s->out_buff1, val );
break;
case AUDIO_SET_WRITE_BUFFER_2:
/* save pointer to buffer 2 */
- s->buffer_2 = val;
+ D( "%s: AUDIO_SET_WRITE_BUFFER_2 %08x", __FUNCTION__, val);
+ goldfish_audio_buff_set_address( s->out_buff2, val );
break;
case AUDIO_WRITE_BUFFER_1:
/* record that data in buffer 1 is ready to write */
+ //D( "%s: AUDIO_WRITE_BUFFER_1 %08x", __FUNCTION__, val);
if (s->current_buffer == 0) s->current_buffer = 1;
- s->data_1 = phys_ram_base + s->buffer_1;
- s->data_1_length = val;
+ goldfish_audio_buff_set_length( s->out_buff1, val );
+ goldfish_audio_buff_read( s->out_buff1 );
s->int_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY;
break;
case AUDIO_WRITE_BUFFER_2:
/* record that data in buffer 2 is ready to write */
+ //D( "%s: AUDIO_WRITE_BUFFER_2 %08x", __FUNCTION__, val);
if (s->current_buffer == 0) s->current_buffer = 2;
- s->data_2 = phys_ram_base + s->buffer_2;
- s->data_2_length = val;
+ goldfish_audio_buff_set_length( s->out_buff2, val );
+ goldfish_audio_buff_read( s->out_buff2 );
s->int_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY;
break;
- case AUDIO_SET_READ_BUFFER:
+ case AUDIO_SET_READ_BUFFER:
/* save pointer to the read buffer */
- s->read_buffer = val;
+ goldfish_audio_buff_set_address( s->in_buff, val );
D( "%s: AUDIO_SET_READ_BUFFER %p", __FUNCTION__, (void*)val );
break;
@@ -350,19 +464,14 @@ static void goldfish_audio_callback(void *opaque, int free)
/* write data in buffer 1 */
while (free && s->current_buffer == 1) {
- int write = s->data_1_length;
- if (write > free) write = free;
-
- int written = AUD_write(s->voice, s->data_1, write);
+ int written = goldfish_audio_buff_send( s->out_buff1, free, s );
if (written) {
- D("%s: sent %d bytes to audio output", __FUNCTION__, write);
- s->data_1 += written;
- s->data_1_length -= written;
+ D("%s: sent %5d bytes to audio output (buffer 1)", __FUNCTION__, written);
free -= written;
- if (s->data_1_length == 0) {
+ if (goldfish_audio_buff_length( s->out_buff1 ) == 0) {
new_status |= AUDIO_INT_WRITE_BUFFER_1_EMPTY;
- s->current_buffer = (s->data_2_length ? 2 : 0);
+ s->current_buffer = (goldfish_audio_buff_length( s->out_buff2 ) ? 2 : 0);
}
} else {
break;
@@ -371,19 +480,14 @@ static void goldfish_audio_callback(void *opaque, int free)
/* write data in buffer 2 */
while (free && s->current_buffer == 2) {
- int write = s->data_2_length;
- if (write > free) write = free;
-
- int written = AUD_write(s->voice, s->data_2, write);
+ int written = goldfish_audio_buff_send( s->out_buff2, free, s );
if (written) {
- D("%s: sent %d bytes to audio output", __FUNCTION__, write);
- s->data_2 += written;
- s->data_2_length -= written;
+ D("%s: sent %5d bytes to audio output (buffer 2)", __FUNCTION__, written);
free -= written;
- if (s->data_2_length == 0) {
+ if (goldfish_audio_buff_length( s->out_buff2 ) == 0) {
new_status |= AUDIO_INT_WRITE_BUFFER_2_EMPTY;
- s->current_buffer = (s->data_1_length ? 1 : 0);
+ s->current_buffer = (goldfish_audio_buff_length( s->out_buff1 ) ? 1 : 0);
}
} else {
break;
@@ -404,36 +508,22 @@ goldfish_audio_in_callback(void *opaque, int avail)
struct goldfish_audio_state *s = opaque;
int new_status = 0;
- if (s->read_pos >= s->read_size)
+ if (goldfish_audio_buff_available( s->in_buff ) == 0 )
return;
- if (0 && s->read_size > 0)
- D("%s: in %d (pos=%d size=%d)", __FUNCTION__,
- avail, s->read_pos, s->read_size );
-
while (avail > 0) {
- int pos = s->read_pos;
- int missing = s->read_size - pos;
- uint8* buffer = (uint8*)phys_ram_base + s->read_buffer + pos;
- int read;
- int avail2 = (avail > missing) ? missing : avail;
-
- read = AUD_read(s->voicein, buffer, avail2);
+ int read = goldfish_audio_buff_recv( s->in_buff, avail, s );
if (read == 0)
break;
- if (avail2 > 0)
- D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read);
-
- s->read_buffer_available += read;
-
avail -= read;
- pos += read;
- if (pos == s->read_size) {
+
+ if (goldfish_audio_buff_available( s->in_buff) == 0) {
new_status |= AUDIO_INT_READ_BUFFER_FULL;
- D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d", __FUNCTION__, s->read_buffer_available);
+ D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d",
+ __FUNCTION__, goldfish_audio_buff_length( s->in_buff ));
+ break;
}
- s->read_pos = pos;
}
if (new_status && new_status != s->int_status) {
@@ -458,7 +548,7 @@ static CPUWriteMemoryFunc *goldfish_audio_writefn[] = {
void goldfish_audio_init(uint32_t base, int id, const char* input_source)
{
struct goldfish_audio_state *s;
- audsettings_t as;
+ struct audsettings as;
/* nothing to do if no audio input and output */
if (!android_hw->hw_audioOutput && !android_hw->hw_audioInput)
@@ -482,7 +572,7 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
}
#endif
- AUD_register_card( &glob_audio_state, "goldfish_audio", &s->card);
+ AUD_register_card( "goldfish_audio", &s->card);
as.freq = 44100;
as.nchannels = 2;
@@ -525,6 +615,10 @@ void goldfish_audio_init(uint32_t base, int id, const char* input_source)
}
#endif
+ goldfish_audio_buff_init( s->out_buff1 );
+ goldfish_audio_buff_init( s->out_buff2 );
+ goldfish_audio_buff_init( s->in_buff );
+
goldfish_device_add(&s->dev, goldfish_audio_readfn, goldfish_audio_writefn, s);
register_savevm( "audio_state", 0, AUDIO_STATE_SAVE_VERSION,