diff options
Diffstat (limited to 'audio/multizone')
-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 |