blob: 0e5589b89b03e7ebd321d3cb50829da2638ad74b [file] [log] [blame]
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -07001/*
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)
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -070043#define MAX_READ_ATTEMPTS 3
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -070044#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
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -070082static struct timespec currentTs;
83
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -070084
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;
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700207 return 0;
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700208 } else {
209 // write() returned UNDERRUN or WOULD_BLOCK, retry
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700210 ALOGE("out_write() write to pipe returned unexpected %16lx", written);
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700211 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
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700221 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 }
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700236 }
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700237 clock_gettime(CLOCK_MONOTONIC, &currentTs);
238 //ALOGV("out_write(bytes=%d) written=%d", bytes, written);
239 return written * audio_stream_frame_size(&stream->common);
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700240}
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{
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700334 //ALOGV("in_read bytes=%u", bytes);
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700335 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
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700353
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700354 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) {
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700360 //ALOGV(" in_read got frames=%u size=%u attempts=%d", remaining_frames, frame_size, attempts);
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700361 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
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700376 //ALOGW("sleeping %dms", READ_ATTEMPT_SLEEP_MS);
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700377 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
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700393 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 }
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700399
400 if (frames_read < 0) {
401 ALOGE("in_read error=%16lx", frames_read);
402 }
Jean-Michel Trivi6acd9662012-09-11 19:19:08 -0700403 ALOGE_IF(attempts == 0, "attempts == 0 ");
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700404 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
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700673static 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;
Eric Laurent5d85c532012-09-10 10:36:09 -0700687 rsxadev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700688 rsxadev->device.common.module = (struct hw_module_t *) module;
689 rsxadev->device.common.close = adev_close;
690
Jean-Michel Trivi88b79cb2012-08-16 13:56:03 -0700691 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"