audio_hw.cpp revision 6acd966320c7f124f103044f3a152d90d6e38749
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "r_submix" 18//#define LOG_NDEBUG 0 19 20#include <errno.h> 21#include <pthread.h> 22#include <stdint.h> 23#include <sys/time.h> 24#include <stdlib.h> 25 26#include <cutils/log.h> 27#include <cutils/str_parms.h> 28#include <cutils/properties.h> 29 30#include <hardware/hardware.h> 31#include <system/audio.h> 32#include <hardware/audio.h> 33 34#include <media/nbaio/Pipe.h> 35#include <media/nbaio/PipeReader.h> 36#include <media/AudioBufferProvider.h> 37 38extern "C" { 39 40namespace android { 41 42#define MAX_PIPE_DEPTH_IN_FRAMES (1024*4) 43#define MAX_READ_ATTEMPTS 3 44#define READ_ATTEMPT_SLEEP_MS 10 // 10ms between two read attempts when pipe is empty 45#define DEFAULT_RATE_HZ 48000 // default sample rate 46 47struct submix_config { 48 audio_format_t format; 49 audio_channel_mask_t channel_mask; 50 unsigned int rate; // sample rate for the device 51 unsigned int period_size; // size of the audio pipe is period_size * period_count in frames 52 unsigned int period_count; 53}; 54 55struct submix_audio_device { 56 struct audio_hw_device device; 57 submix_config config; 58 // Pipe variables: they handle the ring buffer that "pipes" audio: 59 // - from the submix virtual audio output == what needs to be played by 60 // the remotely, seen as an output for AudioFlinger 61 // - to the virtual audio source == what is captured by the component 62 // which "records" the submix / virtual audio source, and handles it as needed. 63 // An usecase example is one where the component capturing the audio is then sending it over 64 // Wifi for presentation on a remote Wifi Display device (e.g. a dongle attached to a TV, or a 65 // TV with Wifi Display capabilities), or to a wireless audio player. 66 sp<Pipe> rsxSink; 67 sp<PipeReader> rsxSource; 68 69 pthread_mutex_t lock; 70}; 71 72struct submix_stream_out { 73 struct audio_stream_out stream; 74 struct submix_audio_device *dev; 75}; 76 77struct submix_stream_in { 78 struct audio_stream_in stream; 79 struct submix_audio_device *dev; 80}; 81 82static struct timespec currentTs; 83 84 85/* audio HAL functions */ 86 87static uint32_t out_get_sample_rate(const struct audio_stream *stream) 88{ 89 const struct submix_stream_out *out = 90 reinterpret_cast<const struct submix_stream_out *>(stream); 91 uint32_t out_rate = out->dev->config.rate; 92 //ALOGV("out_get_sample_rate() returns %u", out_rate); 93 return out_rate; 94} 95 96static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) 97{ 98 if ((rate != 44100) && (rate != 48000)) { 99 ALOGE("out_set_sample_rate(rate=%u) rate unsupported", rate); 100 return -ENOSYS; 101 } 102 struct submix_stream_out *out = reinterpret_cast<struct submix_stream_out *>(stream); 103 //ALOGV("out_set_sample_rate(rate=%u)", rate); 104 out->dev->config.rate = rate; 105 return 0; 106} 107 108static size_t out_get_buffer_size(const struct audio_stream *stream) 109{ 110 const struct submix_stream_out *out = 111 reinterpret_cast<const struct submix_stream_out *>(stream); 112 const struct submix_config& config_out = out->dev->config; 113 size_t buffer_size = config_out.period_size * popcount(config_out.channel_mask) 114 * sizeof(int16_t); // only PCM 16bit 115 //ALOGV("out_get_buffer_size() returns %u, period size=%u", 116 // buffer_size, config_out.period_size); 117 return buffer_size; 118} 119 120static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) 121{ 122 const struct submix_stream_out *out = 123 reinterpret_cast<const struct submix_stream_out *>(stream); 124 uint32_t channels = out->dev->config.channel_mask; 125 //ALOGV("out_get_channels() returns %08x", channels); 126 return channels; 127} 128 129static audio_format_t out_get_format(const struct audio_stream *stream) 130{ 131 return AUDIO_FORMAT_PCM_16_BIT; 132} 133 134static int out_set_format(struct audio_stream *stream, audio_format_t format) 135{ 136 if (format != AUDIO_FORMAT_PCM_16_BIT) { 137 return -ENOSYS; 138 } else { 139 return 0; 140 } 141} 142 143static int out_standby(struct audio_stream *stream) 144{ 145 // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here 146 return 0; 147} 148 149static int out_dump(const struct audio_stream *stream, int fd) 150{ 151 return 0; 152} 153 154static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) 155{ 156 return 0; 157} 158 159static char * out_get_parameters(const struct audio_stream *stream, const char *keys) 160{ 161 return strdup(""); 162} 163 164static uint32_t out_get_latency(const struct audio_stream_out *stream) 165{ 166 const struct submix_stream_out *out = 167 reinterpret_cast<const struct submix_stream_out *>(stream); 168 const struct submix_config * config_out = &(out->dev->config); 169 uint32_t latency = (MAX_PIPE_DEPTH_IN_FRAMES * 1000) / config_out->rate; 170 ALOGV("out_get_latency() returns %u", latency); 171 return latency; 172} 173 174static int out_set_volume(struct audio_stream_out *stream, float left, 175 float right) 176{ 177 return -ENOSYS; 178} 179 180static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, 181 size_t bytes) 182{ 183 //ALOGV("out_write(bytes=%d)", bytes); 184 ssize_t written = 0; 185 struct submix_stream_out *out = reinterpret_cast<struct submix_stream_out *>(stream); 186 187 pthread_mutex_lock(&out->dev->lock); 188 189 Pipe* sink = out->dev->rsxSink.get(); 190 if (sink != NULL) { 191 out->dev->rsxSink->incStrong(buffer); 192 } else { 193 pthread_mutex_unlock(&out->dev->lock); 194 ALOGE("out_write without a pipe!"); 195 ALOG_ASSERT("out_write without a pipe!"); 196 return 0; 197 } 198 199 pthread_mutex_unlock(&out->dev->lock); 200 201 const size_t frames = bytes / audio_stream_frame_size(&stream->common); 202 written = sink->write(buffer, frames); 203 if (written < 0) { 204 if (written == (ssize_t)NEGOTIATE) { 205 ALOGE("out_write() write to pipe returned NEGOTIATE"); 206 written = 0; 207 return 0; 208 } else { 209 // write() returned UNDERRUN or WOULD_BLOCK, retry 210 ALOGE("out_write() write to pipe returned unexpected %16lx", written); 211 written = sink->write(buffer, frames); 212 } 213 } 214 215 pthread_mutex_lock(&out->dev->lock); 216 217 out->dev->rsxSink->decStrong(buffer); 218 219 pthread_mutex_unlock(&out->dev->lock); 220 221 struct timespec newTs; 222 int toSleepUs = 0; 223 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 224 if (rc == 0) { 225 time_t sec = newTs.tv_sec - currentTs.tv_sec; 226 long nsec = newTs.tv_nsec - currentTs.tv_nsec; 227 if (nsec < 0) { 228 --sec; 229 nsec += 1000000000; 230 } 231 if ((nsec / 1000) < (frames * 1000000 / out_get_sample_rate(&stream->common))) { 232 toSleepUs = (frames * 1000000 / out_get_sample_rate(&stream->common)) - (nsec/1000); 233 ALOGI("sleeping %dus", toSleepUs); 234 usleep(toSleepUs); 235 } 236 } 237 clock_gettime(CLOCK_MONOTONIC, ¤tTs); 238 //ALOGV("out_write(bytes=%d) written=%d", bytes, written); 239 return written * audio_stream_frame_size(&stream->common); 240} 241 242static int out_get_render_position(const struct audio_stream_out *stream, 243 uint32_t *dsp_frames) 244{ 245 return -EINVAL; 246} 247 248static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 249{ 250 return 0; 251} 252 253static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 254{ 255 return 0; 256} 257 258static int out_get_next_write_timestamp(const struct audio_stream_out *stream, 259 int64_t *timestamp) 260{ 261 return -EINVAL; 262} 263 264/** audio_stream_in implementation **/ 265static uint32_t in_get_sample_rate(const struct audio_stream *stream) 266{ 267 const struct submix_stream_in *in = reinterpret_cast<const struct submix_stream_in *>(stream); 268 ALOGV("in_get_sample_rate() returns %u", in->dev->config.rate); 269 return in->dev->config.rate; 270} 271 272static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) 273{ 274 return -ENOSYS; 275} 276 277static size_t in_get_buffer_size(const struct audio_stream *stream) 278{ 279 const struct submix_stream_in *in = reinterpret_cast<const struct submix_stream_in *>(stream); 280 ALOGV("in_get_buffer_size() returns %u", 281 in->dev->config.period_size * audio_stream_frame_size(stream)); 282 return in->dev->config.period_size * audio_stream_frame_size(stream); 283} 284 285static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) 286{ 287 return AUDIO_CHANNEL_IN_STEREO; 288} 289 290static audio_format_t in_get_format(const struct audio_stream *stream) 291{ 292 return AUDIO_FORMAT_PCM_16_BIT; 293} 294 295static int in_set_format(struct audio_stream *stream, audio_format_t format) 296{ 297 if (format != AUDIO_FORMAT_PCM_16_BIT) { 298 return -ENOSYS; 299 } else { 300 return 0; 301 } 302} 303 304static int in_standby(struct audio_stream *stream) 305{ 306 // REMOTE_SUBMIX is a proxy / virtual audio device, so the notion of standby doesn't apply here 307 return 0; 308} 309 310static int in_dump(const struct audio_stream *stream, int fd) 311{ 312 return 0; 313} 314 315static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) 316{ 317 return 0; 318} 319 320static char * in_get_parameters(const struct audio_stream *stream, 321 const char *keys) 322{ 323 return strdup(""); 324} 325 326static int in_set_gain(struct audio_stream_in *stream, float gain) 327{ 328 return 0; 329} 330 331static ssize_t in_read(struct audio_stream_in *stream, void* buffer, 332 size_t bytes) 333{ 334 //ALOGV("in_read bytes=%u", bytes); 335 ssize_t frames_read = -1977; 336 const struct submix_stream_in *in = reinterpret_cast<const struct submix_stream_in *>(stream); 337 const size_t frame_size = audio_stream_frame_size(&stream->common); 338 339 pthread_mutex_lock(&in->dev->lock); 340 341 PipeReader* source = in->dev->rsxSource.get(); 342 if (source != NULL) { 343 in->dev->rsxSource->incStrong(in); 344 } else { 345 pthread_mutex_unlock(&in->dev->lock); 346 usleep((bytes / frame_size) * 1000000 / in_get_sample_rate(&stream->common)); 347 memset(buffer, 0, bytes); 348 return bytes; 349 } 350 351 pthread_mutex_unlock(&in->dev->lock); 352 353 354 int attempts = MAX_READ_ATTEMPTS; 355 size_t remaining_frames = bytes / frame_size; 356 char* buff = (char*)buffer; 357 while (attempts > 0) { 358 frames_read = source->read(buff, remaining_frames, AudioBufferProvider::kInvalidPTS); 359 if (frames_read > 0) { 360 //ALOGV(" in_read got frames=%u size=%u attempts=%d", remaining_frames, frame_size, attempts); 361 remaining_frames -= frames_read; 362 buff += frames_read * frame_size; 363 if (remaining_frames == 0) { 364 // TODO simplify code by breaking out of loop 365 366 pthread_mutex_lock(&in->dev->lock); 367 368 in->dev->rsxSource->decStrong(in); 369 370 pthread_mutex_unlock(&in->dev->lock); 371 372 return bytes; 373 } 374 } else if (frames_read == 0) { 375 // TODO sleep should be tied to how much data is expected 376 //ALOGW("sleeping %dms", READ_ATTEMPT_SLEEP_MS); 377 usleep(READ_ATTEMPT_SLEEP_MS*1000); 378 attempts--; 379 } else { // frames_read is an error code 380 if (frames_read != (ssize_t)OVERRUN) { 381 attempts--; 382 } 383 // else OVERRUN: error has been signaled, ok to read, do not decrement counter 384 } 385 } 386 387 pthread_mutex_lock(&in->dev->lock); 388 389 in->dev->rsxSource->decStrong(in); 390 391 pthread_mutex_unlock(&in->dev->lock); 392 393 if (remaining_frames > 0) { 394 ALOGW("remaining_frames = %d", remaining_frames); 395 memset(((char*)buffer)+ bytes - (remaining_frames * frame_size), 0, 396 remaining_frames * frame_size); 397 return bytes; 398 } 399 400 if (frames_read < 0) { 401 ALOGE("in_read error=%16lx", frames_read); 402 } 403 ALOGE_IF(attempts == 0, "attempts == 0 "); 404 return 0; 405} 406 407static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) 408{ 409 return 0; 410} 411 412static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 413{ 414 return 0; 415} 416 417static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 418{ 419 return 0; 420} 421 422static int adev_open_output_stream(struct audio_hw_device *dev, 423 audio_io_handle_t handle, 424 audio_devices_t devices, 425 audio_output_flags_t flags, 426 struct audio_config *config, 427 struct audio_stream_out **stream_out) 428{ 429 ALOGV("adev_open_output_stream()"); 430 struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; 431 struct submix_stream_out *out; 432 int ret; 433 434 out = (struct submix_stream_out *)calloc(1, sizeof(struct submix_stream_out)); 435 if (!out) { 436 ret = -ENOMEM; 437 goto err_open; 438 } 439 440 pthread_mutex_lock(&rsxadev->lock); 441 442 out->stream.common.get_sample_rate = out_get_sample_rate; 443 out->stream.common.set_sample_rate = out_set_sample_rate; 444 out->stream.common.get_buffer_size = out_get_buffer_size; 445 out->stream.common.get_channels = out_get_channels; 446 out->stream.common.get_format = out_get_format; 447 out->stream.common.set_format = out_set_format; 448 out->stream.common.standby = out_standby; 449 out->stream.common.dump = out_dump; 450 out->stream.common.set_parameters = out_set_parameters; 451 out->stream.common.get_parameters = out_get_parameters; 452 out->stream.common.add_audio_effect = out_add_audio_effect; 453 out->stream.common.remove_audio_effect = out_remove_audio_effect; 454 out->stream.get_latency = out_get_latency; 455 out->stream.set_volume = out_set_volume; 456 out->stream.write = out_write; 457 out->stream.get_render_position = out_get_render_position; 458 out->stream.get_next_write_timestamp = out_get_next_write_timestamp; 459 460 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 461 rsxadev->config.channel_mask = config->channel_mask; 462 463 if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) { 464 config->sample_rate = DEFAULT_RATE_HZ; 465 } 466 rsxadev->config.rate = config->sample_rate; 467 468 config->format = AUDIO_FORMAT_PCM_16_BIT; 469 rsxadev->config.format = config->format; 470 471 rsxadev->config.period_size = 1024; 472 rsxadev->config.period_count = 4; 473 out->dev = rsxadev; 474 475 *stream_out = &out->stream; 476 477 // initialize pipe 478 { 479 ALOGV(" initializing pipe"); 480 const NBAIO_Format format = 481 config->sample_rate == 48000 ? Format_SR48_C2_I16 : Format_SR44_1_C2_I16; 482 const NBAIO_Format offers[1] = {format}; 483 size_t numCounterOffers = 0; 484 // creating a Pipe, not a MonoPipe with optional blocking set to true, so audio frames 485 // entering a full sink will overwrite the contents of the pipe. 486 Pipe* sink = new Pipe(MAX_PIPE_DEPTH_IN_FRAMES, format); 487 ssize_t index = sink->negotiate(offers, 1, NULL, numCounterOffers); 488 ALOG_ASSERT(index == 0); 489 PipeReader* source = new PipeReader(*sink); 490 numCounterOffers = 0; 491 index = source->negotiate(offers, 1, NULL, numCounterOffers); 492 ALOG_ASSERT(index == 0); 493 rsxadev->rsxSink = sink; 494 rsxadev->rsxSource = source; 495 } 496 497 pthread_mutex_unlock(&rsxadev->lock); 498 499 return 0; 500 501err_open: 502 *stream_out = NULL; 503 return ret; 504} 505 506static void adev_close_output_stream(struct audio_hw_device *dev, 507 struct audio_stream_out *stream) 508{ 509 ALOGV("adev_close_output_stream()"); 510 struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; 511 512 pthread_mutex_lock(&rsxadev->lock); 513 514 rsxadev->rsxSink.clear(); 515 rsxadev->rsxSource.clear(); 516 free(stream); 517 518 pthread_mutex_unlock(&rsxadev->lock); 519} 520 521static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) 522{ 523 return -ENOSYS; 524} 525 526static char * adev_get_parameters(const struct audio_hw_device *dev, 527 const char *keys) 528{ 529 return strdup("");; 530} 531 532static int adev_init_check(const struct audio_hw_device *dev) 533{ 534 ALOGI("adev_init_check()"); 535 return 0; 536} 537 538static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) 539{ 540 return -ENOSYS; 541} 542 543static int adev_set_master_volume(struct audio_hw_device *dev, float volume) 544{ 545 return -ENOSYS; 546} 547 548static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) 549{ 550 return -ENOSYS; 551} 552 553static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) 554{ 555 return -ENOSYS; 556} 557 558static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) 559{ 560 return -ENOSYS; 561} 562 563static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) 564{ 565 return 0; 566} 567 568static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) 569{ 570 return -ENOSYS; 571} 572 573static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) 574{ 575 return -ENOSYS; 576} 577 578static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, 579 const struct audio_config *config) 580{ 581 //### TODO correlate this with pipe parameters 582 return 4096; 583} 584 585static int adev_open_input_stream(struct audio_hw_device *dev, 586 audio_io_handle_t handle, 587 audio_devices_t devices, 588 struct audio_config *config, 589 struct audio_stream_in **stream_in) 590{ 591 ALOGI("adev_open_input_stream()"); 592 593 struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; 594 struct submix_stream_in *in; 595 int ret; 596 597 in = (struct submix_stream_in *)calloc(1, sizeof(struct submix_stream_in)); 598 if (!in) { 599 ret = -ENOMEM; 600 goto err_open; 601 } 602 603 pthread_mutex_lock(&rsxadev->lock); 604 605 in->stream.common.get_sample_rate = in_get_sample_rate; 606 in->stream.common.set_sample_rate = in_set_sample_rate; 607 in->stream.common.get_buffer_size = in_get_buffer_size; 608 in->stream.common.get_channels = in_get_channels; 609 in->stream.common.get_format = in_get_format; 610 in->stream.common.set_format = in_set_format; 611 in->stream.common.standby = in_standby; 612 in->stream.common.dump = in_dump; 613 in->stream.common.set_parameters = in_set_parameters; 614 in->stream.common.get_parameters = in_get_parameters; 615 in->stream.common.add_audio_effect = in_add_audio_effect; 616 in->stream.common.remove_audio_effect = in_remove_audio_effect; 617 in->stream.set_gain = in_set_gain; 618 in->stream.read = in_read; 619 in->stream.get_input_frames_lost = in_get_input_frames_lost; 620 621 config->channel_mask = AUDIO_CHANNEL_IN_STEREO; 622 rsxadev->config.channel_mask = config->channel_mask; 623 624 if ((config->sample_rate != 48000) || (config->sample_rate != 44100)) { 625 config->sample_rate = DEFAULT_RATE_HZ; 626 } 627 rsxadev->config.rate = config->sample_rate; 628 629 config->format = AUDIO_FORMAT_PCM_16_BIT; 630 rsxadev->config.format = config->format; 631 632 rsxadev->config.period_size = 1024; 633 rsxadev->config.period_count = 4; 634 635 *stream_in = &in->stream; 636 637 in->dev = rsxadev; 638 639 pthread_mutex_unlock(&rsxadev->lock); 640 641 return 0; 642 643err_open: 644 *stream_in = NULL; 645 return ret; 646} 647 648static void adev_close_input_stream(struct audio_hw_device *dev, 649 struct audio_stream_in *stream) 650{ 651 ALOGV("adev_close_input_stream()"); 652 struct submix_audio_device *rsxadev = (struct submix_audio_device *)dev; 653 654 pthread_mutex_lock(&rsxadev->lock); 655 656 free(stream); 657 658 pthread_mutex_unlock(&rsxadev->lock); 659} 660 661static int adev_dump(const audio_hw_device_t *device, int fd) 662{ 663 return 0; 664} 665 666static int adev_close(hw_device_t *device) 667{ 668 ALOGI("adev_close()"); 669 free(device); 670 return 0; 671} 672 673static int adev_open(const hw_module_t* module, const char* name, 674 hw_device_t** device) 675{ 676 ALOGI("adev_open(name=%s)", name); 677 struct submix_audio_device *rsxadev; 678 679 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) 680 return -EINVAL; 681 682 rsxadev = (submix_audio_device*) calloc(1, sizeof(struct submix_audio_device)); 683 if (!rsxadev) 684 return -ENOMEM; 685 686 rsxadev->device.common.tag = HARDWARE_DEVICE_TAG; 687 rsxadev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; 688 rsxadev->device.common.module = (struct hw_module_t *) module; 689 rsxadev->device.common.close = adev_close; 690 691 rsxadev->device.init_check = adev_init_check; 692 rsxadev->device.set_voice_volume = adev_set_voice_volume; 693 rsxadev->device.set_master_volume = adev_set_master_volume; 694 rsxadev->device.get_master_volume = adev_get_master_volume; 695 rsxadev->device.set_master_mute = adev_set_master_mute; 696 rsxadev->device.get_master_mute = adev_get_master_mute; 697 rsxadev->device.set_mode = adev_set_mode; 698 rsxadev->device.set_mic_mute = adev_set_mic_mute; 699 rsxadev->device.get_mic_mute = adev_get_mic_mute; 700 rsxadev->device.set_parameters = adev_set_parameters; 701 rsxadev->device.get_parameters = adev_get_parameters; 702 rsxadev->device.get_input_buffer_size = adev_get_input_buffer_size; 703 rsxadev->device.open_output_stream = adev_open_output_stream; 704 rsxadev->device.close_output_stream = adev_close_output_stream; 705 rsxadev->device.open_input_stream = adev_open_input_stream; 706 rsxadev->device.close_input_stream = adev_close_input_stream; 707 rsxadev->device.dump = adev_dump; 708 709 *device = &rsxadev->device.common; 710 711 return 0; 712} 713 714static struct hw_module_methods_t hal_module_methods = { 715 /* open */ adev_open, 716}; 717 718struct audio_module HAL_MODULE_INFO_SYM = { 719 /* common */ { 720 /* tag */ HARDWARE_MODULE_TAG, 721 /* module_api_version */ AUDIO_MODULE_API_VERSION_0_1, 722 /* hal_api_version */ HARDWARE_HAL_API_VERSION, 723 /* id */ AUDIO_HARDWARE_MODULE_ID, 724 /* name */ "Wifi Display audio HAL", 725 /* author */ "The Android Open Source Project", 726 /* methods */ &hal_module_methods, 727 /* dso */ NULL, 728 /* reserved */ { 0 }, 729 }, 730}; 731 732} //namespace android 733 734} //extern "C" 735