diff options
author | Misael Lopez Cruz | 2013-11-08 02:26:44 -0600 |
---|---|---|
committer | Misael Lopez Cruz | 2013-11-11 17:12:33 -0600 |
commit | 9298ec8849f12a2d30ec1a9bffe1400badf1304b (patch) | |
tree | a66759707aa87acf8d6dd634894ba1963c162a7f | |
parent | d25b28640179643da45a8107efab7922be3d8e54 (diff) | |
download | device-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.tar.gz device-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.tar.xz device-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.zip |
audio: Multizone: Add support for voice call
Voice call is supported using two data pipes:
Uplink:
PcmWriter <-- MonoPipe <-- PcmReader
| |
McASP7 McASP3
| |
Bluetooth Mic
Downlink:
PcmReader --> MonoPipe --> PcmWriter
| |
McASP7 McASP3
| |
Bluetooth Speaker
Voice call reuses the PcmWriter associated with Cabin/Speaker that
is otherwise used for media. So, when the voice call starts any
ongoing media stream active on that writer has to be re-routed to
a null writer and routed back to the actual writer when the voice
call ends.
The null writer is a PcmWriter that writes data to a null output port.
The null port consumes the data at the same rate that the actual port
does. IOW, media streams going to the Cabin output (primary output)
during voice call will not be rendered on the actual hardware output.
Change-Id: I7856b67ab1cf788ea2f2cb251d9097e57e487cb5
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
-rw-r--r-- | audio/multizone/AudioHw.cpp | 325 | ||||
-rw-r--r-- | audio/multizone/AudioHw.h | 39 |
2 files changed, 354 insertions, 10 deletions
diff --git a/audio/multizone/AudioHw.cpp b/audio/multizone/AudioHw.cpp index 9b432e9..a7e3586 100644 --- a/audio/multizone/AudioHw.cpp +++ b/audio/multizone/AudioHw.cpp | |||
@@ -36,8 +36,8 @@ AudioStreamOut::AudioStreamOut(AudioHwDevice *hwDev, | |||
36 | const PcmParams ¶ms, | 36 | const PcmParams ¶ms, |
37 | const SlotMap &map, | 37 | const SlotMap &map, |
38 | audio_devices_t devices) | 38 | audio_devices_t devices) |
39 | : mHwDev(hwDev), mWriter(writer), | 39 | : mHwDev(hwDev), mNullWriter(&mNullPort, params), mWriter(writer), |
40 | mParams(params), mDevices(devices), mStandby(true) | 40 | mParams(params), mDevices(devices), mStandby(true), mUsedForVoiceCall(false) |
41 | { | 41 | { |
42 | if (mWriter) | 42 | if (mWriter) |
43 | mStream = new AdaptedOutStream(params, map); | 43 | mStream = new AdaptedOutStream(params, map); |
@@ -134,7 +134,21 @@ int AudioStreamOut::setFormat(audio_format_t format) | |||
134 | /* must be called with mLock */ | 134 | /* must be called with mLock */ |
135 | int AudioStreamOut::resume() | 135 | int AudioStreamOut::resume() |
136 | { | 136 | { |
137 | int ret = mWriter->registerStream(mStream); | 137 | ALOGV("AudioStreamOut: resume using %s writer", |
138 | mUsedForVoiceCall ? "null" : "regular"); | ||
139 | |||
140 | /* | ||
141 | * Switching PCM writers is done under the assumption that the non-null | ||
142 | * writer (mWriter) is always open (but possibly in standby), which is | ||
143 | * achieved by using the primary output for voice calls. | ||
144 | */ | ||
145 | PcmWriter *writer; | ||
146 | if (mUsedForVoiceCall) | ||
147 | writer = &mNullWriter; | ||
148 | else | ||
149 | writer = mWriter; | ||
150 | |||
151 | int ret = writer->registerStream(mStream); | ||
138 | if (ret) { | 152 | if (ret) { |
139 | ALOGE("AudioStreamOut: failed to register stream %d", ret); | 153 | ALOGE("AudioStreamOut: failed to register stream %d", ret); |
140 | return ret; | 154 | return ret; |
@@ -143,7 +157,7 @@ int AudioStreamOut::resume() | |||
143 | ret = mStream->start(); | 157 | ret = mStream->start(); |
144 | if (ret) { | 158 | if (ret) { |
145 | ALOGE("AudioStreamOut: failed to start stream %d", ret); | 159 | ALOGE("AudioStreamOut: failed to start stream %d", ret); |
146 | mWriter->unregisterStream(mStream); | 160 | writer->unregisterStream(mStream); |
147 | } | 161 | } |
148 | 162 | ||
149 | return ret; | 163 | return ret; |
@@ -152,8 +166,17 @@ int AudioStreamOut::resume() | |||
152 | /* must be called with mLock */ | 166 | /* must be called with mLock */ |
153 | void AudioStreamOut::idle() | 167 | void AudioStreamOut::idle() |
154 | { | 168 | { |
169 | ALOGV("AudioStreamOut: idle using %s writer", | ||
170 | mUsedForVoiceCall ? "null" : "regular"); | ||
171 | |||
172 | PcmWriter *writer; | ||
173 | if (mUsedForVoiceCall) | ||
174 | writer = &mNullWriter; | ||
175 | else | ||
176 | writer = mWriter; | ||
177 | |||
155 | mStream->stop(); | 178 | mStream->stop(); |
156 | mWriter->unregisterStream(mStream); | 179 | writer->unregisterStream(mStream); |
157 | } | 180 | } |
158 | 181 | ||
159 | int AudioStreamOut::standby() | 182 | int AudioStreamOut::standby() |
@@ -170,6 +193,31 @@ int AudioStreamOut::standby() | |||
170 | return 0; | 193 | return 0; |
171 | } | 194 | } |
172 | 195 | ||
196 | void AudioStreamOut::setVoiceCall(bool on) | ||
197 | { | ||
198 | ALOGV("AudioStreamOut: standby()"); | ||
199 | |||
200 | AutoMutex lock(mLock); | ||
201 | |||
202 | /* | ||
203 | * Voice call reuses one of the PCM writers that is otherwise used | ||
204 | * for media. Media has to be re-routed to a null writer (that only | ||
205 | * consumes the data but doesn't write it to the hardware) when the | ||
206 | * voice call starts and routed back to the actual writer when the | ||
207 | * voice call stops. | ||
208 | * Temporarily entering standby helps transitioning to the null writer | ||
209 | * the next time that data is written to the stream if the voice call | ||
210 | * occurs at mid-stream. | ||
211 | */ | ||
212 | if (mUsedForVoiceCall != on) { | ||
213 | if (!mStandby) { | ||
214 | idle(); | ||
215 | mStandby = true; | ||
216 | } | ||
217 | mUsedForVoiceCall = on; | ||
218 | } | ||
219 | } | ||
220 | |||
173 | int AudioStreamOut::dump(int fd) const | 221 | int AudioStreamOut::dump(int fd) const |
174 | { | 222 | { |
175 | ALOGV("AudioStreamOut: dump()"); | 223 | ALOGV("AudioStreamOut: dump()"); |
@@ -549,8 +597,11 @@ uint32_t AudioStreamIn::getInputFramesLost() | |||
549 | 597 | ||
550 | /* ---------------------------------------------------------------------------------------- */ | 598 | /* ---------------------------------------------------------------------------------------- */ |
551 | 599 | ||
600 | const char *AudioHwDevice::kCabinVolumeHP = "HP DAC Playback Volume"; | ||
601 | const char *AudioHwDevice::kCabinVolumeLine = "Line DAC Playback Volume"; | ||
602 | |||
552 | AudioHwDevice::AudioHwDevice(uint32_t card) | 603 | AudioHwDevice::AudioHwDevice(uint32_t card) |
553 | : mCardId(card), mMixer(mCardId), mMicMute(false) | 604 | : mCardId(card), mMixer(mCardId), mMicMute(false), mMode(AUDIO_MODE_NORMAL) |
554 | { | 605 | { |
555 | ALOGI("AudioHwDevice: create hw device for card hw:%u", card); | 606 | ALOGI("AudioHwDevice: create hw device for card hw:%u", card); |
556 | 607 | ||
@@ -583,6 +634,34 @@ AudioHwDevice::AudioHwDevice(uint32_t card) | |||
583 | writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1); | 634 | writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1); |
584 | mWriters.push_back(writer); | 635 | mWriters.push_back(writer); |
585 | 636 | ||
637 | /* Voice call */ | ||
638 | PcmParams paramsBT(kBTNumChannels, kSampleSize, kBTSampleRate, kBTFrameCount); | ||
639 | writer = new PcmWriter(mOutPorts[kBTPortId], paramsBT); | ||
640 | mWriters.push_back(writer); | ||
641 | reader = new PcmReader(mInPorts[kBTPortId], paramsBT); | ||
642 | mReaders.push_back(reader); | ||
643 | |||
644 | /* BT is configured as stereo but only the left channel carries data */ | ||
645 | SlotMap slots; | ||
646 | slots[0] = 0; | ||
647 | slots[1] = 0; | ||
648 | |||
649 | /* Voice call uplink */ | ||
650 | mULPipe = new tiaudioutils::MonoPipe(paramsBT, | ||
651 | (kVoiceCallPipeMs * paramsBT.sampleRate) / 1000); | ||
652 | mULPipeWriter = new PipeWriter(mULPipe); | ||
653 | mULPipeReader = new PipeReader(mULPipe); | ||
654 | mVoiceULInStream = new InStream(paramsBT, slots, mULPipeWriter); | ||
655 | mVoiceULOutStream = new OutStream(paramsBT, slots, mULPipeReader); | ||
656 | |||
657 | /* Voice call downlink */ | ||
658 | mDLPipe = new tiaudioutils::MonoPipe(paramsBT, | ||
659 | (kVoiceCallPipeMs * params0.sampleRate) / 1000); | ||
660 | mDLPipeWriter = new PipeWriter(mDLPipe); | ||
661 | mDLPipeReader = new PipeReader(mDLPipe); | ||
662 | mVoiceDLInStream = new InStream(paramsBT, slots, mDLPipeWriter); | ||
663 | mVoiceDLOutStream = new OutStream(paramsBT, slots, mDLPipeReader); | ||
664 | |||
586 | mMixer.initRoutes(); | 665 | mMixer.initRoutes(); |
587 | } | 666 | } |
588 | 667 | ||
@@ -590,6 +669,24 @@ AudioHwDevice::~AudioHwDevice() | |||
590 | { | 669 | { |
591 | ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId); | 670 | ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId); |
592 | 671 | ||
672 | if (mDLPipeWriter) | ||
673 | delete mDLPipeWriter; | ||
674 | |||
675 | if (mDLPipeReader) | ||
676 | delete mDLPipeReader; | ||
677 | |||
678 | if (mDLPipe) | ||
679 | delete mDLPipe; | ||
680 | |||
681 | if (mULPipeWriter) | ||
682 | delete mULPipeWriter; | ||
683 | |||
684 | if (mULPipeReader) | ||
685 | delete mULPipeReader; | ||
686 | |||
687 | if (mULPipe) | ||
688 | delete mULPipe; | ||
689 | |||
593 | for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { | 690 | for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { |
594 | delete (*i); | 691 | delete (*i); |
595 | } | 692 | } |
@@ -640,13 +737,49 @@ int AudioHwDevice::initCheck() const | |||
640 | } | 737 | } |
641 | } | 738 | } |
642 | 739 | ||
740 | if ((mULPipe == NULL) || !mULPipe->initCheck() || | ||
741 | (mULPipeReader == NULL) || !mULPipeReader->initCheck() || | ||
742 | (mULPipeWriter == NULL) || !mULPipeWriter->initCheck()) { | ||
743 | ALOGE("AudioHwDevice: voice call uplink init check failed"); | ||
744 | return -ENODEV; | ||
745 | } | ||
746 | |||
747 | if ((mDLPipe == NULL) || !mDLPipe->initCheck() || | ||
748 | (mDLPipeReader == NULL) || !mDLPipeReader->initCheck() || | ||
749 | (mDLPipeWriter == NULL) || !mDLPipeWriter->initCheck()) { | ||
750 | ALOGE("AudioHwDevice: voice call downlink init check failed"); | ||
751 | return -ENODEV; | ||
752 | } | ||
753 | |||
754 | if ((mVoiceULInStream == NULL) || !mVoiceULInStream->initCheck() || | ||
755 | (mVoiceULOutStream == NULL) || !mVoiceULOutStream->initCheck()) { | ||
756 | ALOGE("AudioHwDevice: voice call uplink streams init check failed"); | ||
757 | return -ENODEV; | ||
758 | } | ||
759 | |||
760 | if ((mVoiceDLInStream == NULL) || !mVoiceDLInStream->initCheck() || | ||
761 | (mVoiceDLOutStream == NULL) || !mVoiceDLOutStream->initCheck()) { | ||
762 | ALOGE("AudioHwDevice: voice call downlink streams init check failed"); | ||
763 | return -ENODEV; | ||
764 | } | ||
765 | |||
643 | return 0; | 766 | return 0; |
644 | } | 767 | } |
645 | 768 | ||
646 | int AudioHwDevice::setVoiceVolume(float volume) | 769 | int AudioHwDevice::setVoiceVolume(float volume) |
647 | { | 770 | { |
648 | ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f", volume); | 771 | /* Linear interpolation between voice dB limits */ |
649 | return -ENOSYS; | 772 | float dB = (kVoiceDBMax - kVoiceDBMin) * volume + kVoiceDBMin; |
773 | |||
774 | /* Output stage gain (-59.0dB, 0dB) with steps of 0.5dB */ | ||
775 | int val = 2 * (dB + 59.0f); | ||
776 | |||
777 | ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f dB=%.4f", volume, dB, val); | ||
778 | |||
779 | mMixer.set(ALSAControl(kCabinVolumeHP, val), true); | ||
780 | mMixer.set(ALSAControl(kCabinVolumeLine, val), true); | ||
781 | |||
782 | return 0; | ||
650 | } | 783 | } |
651 | 784 | ||
652 | int AudioHwDevice::setMasterVolume(float volume) | 785 | int AudioHwDevice::setMasterVolume(float volume) |
@@ -677,7 +810,162 @@ int AudioHwDevice::setMode(audio_mode_t mode) | |||
677 | { | 810 | { |
678 | ALOGV("AudioHwDevice: setMode() %s", getModeName(mode)); | 811 | ALOGV("AudioHwDevice: setMode() %s", getModeName(mode)); |
679 | 812 | ||
680 | return 0; | 813 | AutoMutex lock(mLock); |
814 | if (mMode == mode) { | ||
815 | ALOGW("AudioHwDevice: already in mode %s", getModeName(mode)); | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | int ret = 0; | ||
820 | if (mode == AUDIO_MODE_IN_CALL) { | ||
821 | ret = enterVoiceCall(); | ||
822 | ALOGE_IF(ret, "AudioHwDevice: failed to enter voice call %d", ret); | ||
823 | } else { | ||
824 | leaveVoiceCall(); | ||
825 | } | ||
826 | |||
827 | if (!ret) | ||
828 | mMode = mode; | ||
829 | |||
830 | return ret; | ||
831 | } | ||
832 | |||
833 | int AudioHwDevice::enableVoiceCall() | ||
834 | { | ||
835 | ALOGV("AudioHwDevice: enable voice call paths"); | ||
836 | |||
837 | sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote(); | ||
838 | if (outStream == NULL) { | ||
839 | ALOGE("AudioHwDevice: primary output stream is not valid"); | ||
840 | return -ENODEV; | ||
841 | } | ||
842 | |||
843 | /* Playback stream will free the writer and switch to a null writer */ | ||
844 | outStream->setVoiceCall(true); | ||
845 | |||
846 | /* Uplink input stream: Mic -> Pipe */ | ||
847 | int ret = mReaders[kCPUPortId]->registerStream(mVoiceULInStream); | ||
848 | if (ret) { | ||
849 | ALOGE("AudioHwDevice: failed to register uplink in stream %d", ret); | ||
850 | return ret; | ||
851 | } | ||
852 | |||
853 | /* Uplink output stream: Pipe -> Bluetooth */ | ||
854 | ret = mWriters[kBTPortId]->registerStream(mVoiceULOutStream); | ||
855 | if (ret) { | ||
856 | ALOGE("AudioHwDevice: failed to register uplink out stream %d", ret); | ||
857 | return ret; | ||
858 | } | ||
859 | |||
860 | /* Downlink input stream: Bluetooth -> Pipe */ | ||
861 | ret = mReaders[kBTPortId]->registerStream(mVoiceDLInStream); | ||
862 | if (ret) { | ||
863 | ALOGE("AudioHwDevice: failed to register downlink in stream %d", ret); | ||
864 | return ret; | ||
865 | } | ||
866 | |||
867 | /* Downlink output stream: Pipe -> Speaker */ | ||
868 | ret = outStream->mWriter->registerStream(mVoiceDLOutStream); | ||
869 | if (ret) { | ||
870 | ALOGE("AudioHwDevice: failed to register downlink out stream %d", ret); | ||
871 | } | ||
872 | |||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | void AudioHwDevice::disableVoiceCall() | ||
877 | { | ||
878 | ALOGV("AudioHwDevice: disable voice call paths"); | ||
879 | |||
880 | sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote(); | ||
881 | if (outStream != NULL) { | ||
882 | outStream->setVoiceCall(false); | ||
883 | if (outStream->mWriter->isStreamRegistered(mVoiceDLOutStream)) | ||
884 | outStream->mWriter->unregisterStream(mVoiceDLOutStream); | ||
885 | } else { | ||
886 | ALOGE("AudioHwDevice: primary output stream is not valid"); | ||
887 | } | ||
888 | |||
889 | if (mReaders[kBTPortId]->isStreamRegistered(mVoiceDLInStream)) | ||
890 | mReaders[kBTPortId]->unregisterStream(mVoiceDLInStream); | ||
891 | |||
892 | if (mWriters[kBTPortId]->isStreamRegistered(mVoiceULOutStream)) | ||
893 | mWriters[kBTPortId]->unregisterStream(mVoiceULOutStream); | ||
894 | |||
895 | if (mReaders[kCPUPortId]->isStreamRegistered(mVoiceULInStream)) | ||
896 | mReaders[kCPUPortId]->unregisterStream(mVoiceULInStream); | ||
897 | } | ||
898 | |||
899 | int AudioHwDevice::enterVoiceCall() | ||
900 | { | ||
901 | ALOGI("AudioHwDevice: enter voice call"); | ||
902 | |||
903 | /* Setup uplink and downlink pipes */ | ||
904 | int ret = enableVoiceCall(); | ||
905 | if (ret) { | ||
906 | ALOGE("AudioHwDevice: failed to enable voice call path %d", ret); | ||
907 | return ret; | ||
908 | } | ||
909 | |||
910 | /* Uplink input stream: Mic -> Pipe */ | ||
911 | ret = mVoiceULInStream->start(); | ||
912 | if (ret) { | ||
913 | ALOGE("AudioHwDevice: failed to start uplink in stream %d", ret); | ||
914 | return ret; | ||
915 | } | ||
916 | |||
917 | /* Downlink input stream: Bluetooth -> Pipe */ | ||
918 | ret = mVoiceDLInStream->start(); | ||
919 | if (ret) { | ||
920 | ALOGE("AudioHwDevice: failed to start downlink in stream %d", ret); | ||
921 | return ret; | ||
922 | } | ||
923 | |||
924 | /* | ||
925 | * Wait till pipe is half full to give a head start to the output streams. | ||
926 | * The time to wait consists of the actual pipe size, the ADC settle time | ||
927 | * used in the kernel and the time needed to produce a BT audio buffer. | ||
928 | * Only the pipe size related time contributes to the steady state latency. | ||
929 | */ | ||
930 | usleep((kVoiceCallPipeMs * 5000) + (kADCSettleMs * 1000) + | ||
931 | (kBTFrameCount * 1000) / kBTSampleRate); | ||
932 | |||
933 | /* Downlink output stream: Pipe -> Speaker */ | ||
934 | ret = mVoiceDLOutStream->start(); | ||
935 | if (ret) { | ||
936 | ALOGE("AudioHwDevice: failed to start downlink out stream %d", ret); | ||
937 | } | ||
938 | |||
939 | /* Uplink output stream: Pipe -> Bluetooth */ | ||
940 | ret = mVoiceULOutStream->start(); | ||
941 | if (ret) { | ||
942 | ALOGE("AudioHwDevice: failed to start uplink out stream %d", ret); | ||
943 | return ret; | ||
944 | } | ||
945 | |||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | void AudioHwDevice::leaveVoiceCall() | ||
950 | { | ||
951 | ALOGI("AudioHwDevice: leave voice call"); | ||
952 | |||
953 | if (mVoiceDLOutStream->isStarted()) | ||
954 | mVoiceDLOutStream->stop(); | ||
955 | |||
956 | if (mVoiceULInStream->isStarted()) | ||
957 | mVoiceULInStream->stop(); | ||
958 | |||
959 | if (mVoiceULOutStream->isStarted()) | ||
960 | mVoiceULOutStream->stop(); | ||
961 | |||
962 | if (mVoiceDLInStream->isStarted()) | ||
963 | mVoiceDLInStream->stop(); | ||
964 | |||
965 | disableVoiceCall(); | ||
966 | |||
967 | /* Reset the cabin volume for media */ | ||
968 | setVoiceVolume(1.0f); | ||
681 | } | 969 | } |
682 | 970 | ||
683 | int AudioHwDevice::setMicMute(bool state) | 971 | int AudioHwDevice::setMicMute(bool state) |
@@ -716,6 +1004,7 @@ size_t AudioHwDevice::getInputBufferSize(const struct audio_config *config) cons | |||
716 | { | 1004 | { |
717 | ALOGV("AudioHwDevice: getInputBufferSize()"); | 1005 | ALOGV("AudioHwDevice: getInputBufferSize()"); |
718 | 1006 | ||
1007 | AutoMutex lock(mLock); | ||
719 | size_t size; | 1008 | size_t size; |
720 | 1009 | ||
721 | /* Take resampling ratio into account and align to the nearest | 1010 | /* Take resampling ratio into account and align to the nearest |
@@ -788,6 +1077,12 @@ AudioStreamIn* AudioHwDevice::openInputStream(audio_io_handle_t handle, | |||
788 | } | 1077 | } |
789 | 1078 | ||
790 | SlotMap slotMap(srcMask, dstMask); | 1079 | SlotMap slotMap(srcMask, dstMask); |
1080 | if (!slotMap.isValid()) { | ||
1081 | ALOGE("AudioHwDevice: failed to create slot map"); | ||
1082 | return NULL; | ||
1083 | } | ||
1084 | |||
1085 | AutoMutex lock(mLock); | ||
791 | 1086 | ||
792 | /* Set the parameters for the internal input stream. Don't change the | 1087 | /* Set the parameters for the internal input stream. Don't change the |
793 | * parameters for capture. The resampler is used if needed. */ | 1088 | * parameters for capture. The resampler is used if needed. */ |
@@ -810,6 +1105,8 @@ void AudioHwDevice::closeInputStream(AudioStreamIn *in) | |||
810 | { | 1105 | { |
811 | ALOGV("AudioHwDevice: closeInputStream()"); | 1106 | ALOGV("AudioHwDevice: closeInputStream()"); |
812 | 1107 | ||
1108 | AutoMutex lock(mLock); | ||
1109 | |||
813 | if (mInStreams.find(in) == mInStreams.end()) { | 1110 | if (mInStreams.find(in) == mInStreams.end()) { |
814 | ALOGW("AudioHwDevice: input stream %p is not open", in); | 1111 | ALOGW("AudioHwDevice: input stream %p is not open", in); |
815 | return; | 1112 | return; |
@@ -856,6 +1153,8 @@ AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle, | |||
856 | return NULL; | 1153 | return NULL; |
857 | } | 1154 | } |
858 | 1155 | ||
1156 | AutoMutex lock(mLock); | ||
1157 | |||
859 | /* Set the parameters for the internal output stream */ | 1158 | /* Set the parameters for the internal output stream */ |
860 | params.frameCount = mWriters[port]->getParams().frameCount; | 1159 | params.frameCount = mWriters[port]->getParams().frameCount; |
861 | params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */ | 1160 | params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */ |
@@ -883,6 +1182,9 @@ AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle, | |||
883 | return NULL; | 1182 | return NULL; |
884 | } | 1183 | } |
885 | 1184 | ||
1185 | if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) | ||
1186 | mPrimaryStreamOut = out; | ||
1187 | |||
886 | mOutStreams.insert(out); | 1188 | mOutStreams.insert(out); |
887 | 1189 | ||
888 | return out.get(); | 1190 | return out.get(); |
@@ -892,11 +1194,16 @@ void AudioHwDevice::closeOutputStream(AudioStreamOut *out) | |||
892 | { | 1194 | { |
893 | ALOGV("AudioHwDevice: closeOutputStream()"); | 1195 | ALOGV("AudioHwDevice: closeOutputStream()"); |
894 | 1196 | ||
1197 | AutoMutex lock(mLock); | ||
1198 | |||
895 | if (mOutStreams.find(out) == mOutStreams.end()) { | 1199 | if (mOutStreams.find(out) == mOutStreams.end()) { |
896 | ALOGW("AudioHwDevice: output stream %p is not open", out); | 1200 | ALOGW("AudioHwDevice: output stream %p is not open", out); |
897 | return; | 1201 | return; |
898 | } | 1202 | } |
899 | 1203 | ||
1204 | if (mPrimaryStreamOut == out) | ||
1205 | mPrimaryStreamOut = NULL; | ||
1206 | |||
900 | mOutStreams.erase(out); | 1207 | mOutStreams.erase(out); |
901 | 1208 | ||
902 | out = NULL; | 1209 | out = NULL; |
diff --git a/audio/multizone/AudioHw.h b/audio/multizone/AudioHw.h index a0973ad..2a8a2cc 100644 --- a/audio/multizone/AudioHw.h +++ b/audio/multizone/AudioHw.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <hardware/audio_effect.h> | 23 | #include <hardware/audio_effect.h> |
24 | 24 | ||
25 | #include <tiaudioutils/Pcm.h> | 25 | #include <tiaudioutils/Pcm.h> |
26 | #include <tiaudioutils/NullPcm.h> | ||
26 | #include <tiaudioutils/ALSAPcm.h> | 27 | #include <tiaudioutils/ALSAPcm.h> |
27 | #include <tiaudioutils/ALSAMixer.h> | 28 | #include <tiaudioutils/ALSAMixer.h> |
28 | #include <tiaudioutils/MumStream.h> | 29 | #include <tiaudioutils/MumStream.h> |
@@ -87,16 +88,23 @@ class AudioStreamOut : public RefBase, public AudioStream { | |||
87 | int getRenderPosition(uint32_t *dsp_frames) const; | 88 | int getRenderPosition(uint32_t *dsp_frames) const; |
88 | int getNextWriteTimestamp(int64_t *timestamp) const; | 89 | int getNextWriteTimestamp(int64_t *timestamp) const; |
89 | 90 | ||
91 | void setVoiceCall(bool on); | ||
92 | |||
93 | friend AudioHwDevice; | ||
94 | |||
90 | protected: | 95 | protected: |
91 | int resume(); | 96 | int resume(); |
92 | void idle(); | 97 | void idle(); |
93 | 98 | ||
94 | AudioHwDevice *mHwDev; | 99 | AudioHwDevice *mHwDev; |
100 | NullOutPort mNullPort; | ||
101 | PcmWriter mNullWriter; | ||
95 | PcmWriter *mWriter; | 102 | PcmWriter *mWriter; |
96 | PcmParams mParams; | 103 | PcmParams mParams; |
97 | audio_devices_t mDevices; | 104 | audio_devices_t mDevices; |
98 | sp<OutStream> mStream; | 105 | sp<OutStream> mStream; |
99 | bool mStandby; | 106 | bool mStandby; |
107 | bool mUsedForVoiceCall; | ||
100 | Mutex mLock; | 108 | Mutex mLock; |
101 | }; | 109 | }; |
102 | 110 | ||
@@ -174,16 +182,28 @@ class AudioHwDevice { | |||
174 | friend class AudioStreamIn; | 182 | friend class AudioStreamIn; |
175 | friend class AudioStreamOut; | 183 | friend class AudioStreamOut; |
176 | 184 | ||
177 | static const uint32_t kNumPorts = 2; | 185 | static const uint32_t kNumPorts = 3; |
178 | static const uint32_t kCPUPortId = 0; | 186 | static const uint32_t kCPUPortId = 0; |
179 | static const uint32_t kJAMR3PortId = 1; | 187 | static const uint32_t kJAMR3PortId = 1; |
188 | static const uint32_t kBTPortId = 2; | ||
180 | static const uint32_t kCPUNumChannels = 2; | 189 | static const uint32_t kCPUNumChannels = 2; |
181 | static const uint32_t kJAMR3NumChannels = 8; | 190 | static const uint32_t kJAMR3NumChannels = 8; |
191 | static const uint32_t kBTNumChannels = 2; | ||
182 | 192 | ||
183 | static const uint32_t kSampleRate = 44100; | 193 | static const uint32_t kSampleRate = 44100; |
194 | static const uint32_t kBTSampleRate = 8000; | ||
184 | static const uint32_t kSampleSize = 16; | 195 | static const uint32_t kSampleSize = 16; |
185 | static const uint32_t kCaptureFrameCount = 882; | 196 | static const uint32_t kCaptureFrameCount = 882; |
186 | static const uint32_t kPlaybackFrameCount = 1024; | 197 | static const uint32_t kPlaybackFrameCount = 1024; |
198 | static const uint32_t kBTFrameCount = 160; | ||
199 | |||
200 | static const uint32_t kADCSettleMs = 80; | ||
201 | static const uint32_t kVoiceCallPipeMs = 100; | ||
202 | |||
203 | static const float kVoiceDBMax = 0.0f; | ||
204 | static const float kVoiceDBMin = -24.0f; | ||
205 | static const char *kCabinVolumeHP; | ||
206 | static const char *kCabinVolumeLine; | ||
187 | 207 | ||
188 | protected: | 208 | protected: |
189 | typedef set< sp<AudioStreamIn> > StreamInSet; | 209 | typedef set< sp<AudioStreamIn> > StreamInSet; |
@@ -194,6 +214,10 @@ class AudioHwDevice { | |||
194 | typedef vector<PcmWriter*> WriterVect; | 214 | typedef vector<PcmWriter*> WriterVect; |
195 | 215 | ||
196 | const char *getModeName(audio_mode_t mode) const; | 216 | const char *getModeName(audio_mode_t mode) const; |
217 | int enterVoiceCall(); | ||
218 | void leaveVoiceCall(); | ||
219 | int enableVoiceCall(); | ||
220 | void disableVoiceCall(); | ||
197 | 221 | ||
198 | uint32_t mCardId; | 222 | uint32_t mCardId; |
199 | ALSAMixer mMixer; | 223 | ALSAMixer mMixer; |
@@ -204,6 +228,19 @@ class AudioHwDevice { | |||
204 | StreamInSet mInStreams; | 228 | StreamInSet mInStreams; |
205 | StreamOutSet mOutStreams; | 229 | StreamOutSet mOutStreams; |
206 | bool mMicMute; | 230 | bool mMicMute; |
231 | audio_mode_t mMode; | ||
232 | wp<AudioStreamOut> mPrimaryStreamOut; | ||
233 | tiaudioutils::MonoPipe *mULPipe; | ||
234 | tiaudioutils::MonoPipe *mDLPipe; | ||
235 | PipeWriter *mULPipeWriter; | ||
236 | PipeWriter *mDLPipeWriter; | ||
237 | PipeReader *mULPipeReader; | ||
238 | PipeReader *mDLPipeReader; | ||
239 | sp<InStream> mVoiceULInStream; | ||
240 | sp<InStream> mVoiceDLInStream; | ||
241 | sp<OutStream> mVoiceULOutStream; | ||
242 | sp<OutStream> mVoiceDLOutStream; | ||
243 | mutable Mutex mLock; | ||
207 | }; | 244 | }; |
208 | 245 | ||
209 | }; // namespace android | 246 | }; // namespace android |