HFP Client SCO audio routing?

A delay is not going to do the job.

I wouldn’t put too much value into a brand name. Even after looking over the specifications on that card, it doesn’t appear that those specifications are actually being brought out in the alsa driver (for example, they claim 96 kHz sample rate, and you can see from tinypcminfo that it is ONLY advertising 44.1 kHz). I can think of two possible reasons for this;

  1. Their specifications are actually a lie, and they are faking it in their windows driver,
  2. They are implementing some of their specifications using a proprietary interface that does not conform to USB audio device class specifications, which again, would be exclusively through their windows driver.

Now in contrast, my card has 96 kHz listed in its specifications, and it ACTUALLY IS available via ALSA.

Creative labs is an old time technology company that got their name back in the dark ages of computers – the 1990’s, when closed source dominated. They seem to have kept a lot of that mind set and are almost hostile towards anything open source. If you are a Linux user, you do NOT buy anything from Creative labs.

In fact, I did not think too much to buy the sound card. It is only for demo, so the requirement is that it can play sound and has a mic for sound input.

By the way, if a delay can not make it work, which function I can use to close the opened stream then I can open a new one?

Before I can close the opened stream, I have to get the handle of the opened one. That’s what I don’t know how to do.

You will find your existing audio streams in the audio_device struct, output_stream_list and input_stream_list.

The functions in the audio hal that you will be most interested in will probably be these;

out_write,
adev_open_output_stream,
adev_close_output_stream,
in_read,
adev_open_input_stream,
adev_close_input_stream

I’ve done some cleanup, no more changes needed to the default usb audio hal, that’s moved back to the device tree.

One patch needed there;

I write some code to close the existing stream and open a new stream today.
After testing the result, I found some things as following:
There are three senarios:

  1. iphone ← phone call → android<—BT—>hikey960
    I got following messages by “logcat | grep usbaudio”
01-24 08:48:38.392  3935  3976 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_set_sampling_rate=8000
01-24 08:48:38.393  3935  3976 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_enable=true
01-24 08:48:38.393  3935  5107 D modules.usbaudio_hal.hikey: runsco: USBCARD: 1, BTCARD: 0
01-24 08:48:38.394  3935  3976 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_volume=11
01-24 08:48:38.419  3935  5107 D modules.usbaudio_hal.hikey: runsco: failed to open PCM near/out
01-24 08:48:38.526  3935  5107 D modules.usbaudio_hal.hikey: runsco: PCM loop starting

Although opening the PCM near/out was failed, I close the existing stream and open a new one.
The program keep running until the function pcm_read() is called. It just stops there and after a few seconds, system reboot(caused by watchdog?)

  1. android ← phone call → iphone<—BT—>hikey960
    if I dial number on android, I’ll get following messages:
01-24 08:52:02.935  5284  5862 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_set_sampling_rate=8000
01-24 08:52:02.935  5284  5862 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_enable=true
01-24 08:52:02.936  5284  6456 D modules.usbaudio_hal.hikey: runsco: USBCARD: 1, BTCARD: 0
01-24 08:52:02.936  5284  5862 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_volume=11
01-24 08:52:02.985  5284  6456 D modules.usbaudio_hal.hikey: runsco: PCM loop starting
01-24 08:52:03.113  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.146  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.146  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.169  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.169  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.192  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:03.193  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
... ....

after accepting the phone call
01-24 08:52:05.561  5284  6456 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:52:05.583  5284  5806 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_enable=false
01-24 08:52:05.584  5284  6456 D modules.usbaudio_hal.hikey: runsco: PCM loop terminated

It’s quite strange, why hfp_enable=false ? And of course, I can not hear anything from the USB sound card.

  1. If I dial number on iphone, I can here ring tone from USB sound card and I can also hear sound from the android.
    Speak into the android phone, I can also here sound from USB sound card. Everything is fine.
01-24 08:53:59.944  5284  5284 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_set_sampling_rate=8000
01-24 08:53:59.947  5284  5284 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_enable=true
01-24 08:53:59.947  5284  6571 D modules.usbaudio_hal.hikey: runsco: USBCARD: 1, BTCARD: 0
01-24 08:53:59.947  5284  5284 D modules.usbaudio_hal.hikey: adev_set_parameters: kvpairs: hfp_volume=11
01-24 08:54:00.008  5284  6571 D modules.usbaudio_hal.hikey: runsco: PCM loop starting
01-24 08:54:00.136  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.170  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.170  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.191  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.191  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.214  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.215  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.237  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.238  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.261  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
01-24 08:54:00.261  5284  6571 D modules.usbaudio_hal.hikey: runsco: Looping...
... ...

And this case has NO “failed to open PCM near/out” message.

I think maybe I should utilize the existing stream instead of closing it and open a new one.
I also ordered a new USB sound card which supports 48K sampling rate, and I can test it tomorrow to see if there is any difference between the Creative USB sound card and the new one.

For your diagrams like "android<—BT—>hikey960<–phone call–> iPhone"
They are a little bit confusing because they are implying an incorrect relationship between the devices. There is no “phone call” between the hikey960 and anything, since it does not have phone hardware. What you mean is actually like this;
iphone <-- phone call --> android<—BT—>hikey960

For scenario 1, it appears that you made changes to the code around pcm_open. In my code, if any of the PCM’s fail to open, the function will return and not proceed to the PCM loop; https://github.com/lbdroid/android_device_linaro_hikey/blob/master/usbaudio/audio_hal.c#L1310

Now my question for you about what you did to close existing streams… did you do anything to prevent it from opening another one between closing it and opening your own?

For scenario 2, note that at the moment when you accept the call, it is expected to close the SCO that is already open, but normally, it should open another one immediately. The reason for the multiple SCO connections has to do with, I believe, something called “in band ringing”. It basically means that the ringtone it is playing would be the one you selected on the PHONE, not the one you selected on the hikey.

On my cell phone (Pixel 2 XL), I have an option in DEVELOPER OPTIONS, to enable or disable in-band ringing. I have it enabled. It creates first an SCO connection for the ringing, then upon accept call, it closes that SCO, and opens another.

Now the reason why I prefer to open the connection to the USB card myself, is that you can’t necessarily guarantee that there will be an existing open stream. There probably will be, but that is not certain.

Oh, the diagram is wrong, I have corrected it.

Here is my code:

adev->sco_pcm_near_out = pcm_open(adev->usbcard, 0, PCM_OUT, &usb_config);
    if (adev->sco_pcm_near_out == 0) {
        ALOGD("%s: failed to allocate memory for PCM near/out", __func__);
        return NULL;
    } else if (!pcm_is_ready(adev->sco_pcm_near_out)){
        pcm_close(adev->sco_pcm_near_out);
        ALOGD("%s: failed to open PCM near/out", __func__);
        
        struct listnode* node;
        list_for_each(node, &adev->output_stream_list) {
                struct audio_stream* stream =
                        (struct audio_stream *)node_to_item(node, struct stream_out, list_node);
                 adev_close_output_stream(NULL,(struct audio_stream_out *)stream);
         }

	adev->sco_pcm_near_out = pcm_open(adev->usbcard, 0, PCM_OUT, &usb_config);
	if (adev->sco_pcm_near_out == 0) {
        	ALOGD("%s: failed to allocate memory for PCM near/out", __func__);
        	return NULL;
	} 
	else if (!pcm_is_ready(adev->sco_pcm_near_out)){
		pcm_close(adev->sco_pcm_near_out);
        	ALOGD("%s:reopen failed to open PCM near/out", __func__);
		return NULL;
      }
 }

Anything wrong?

Ok, then the line "runsco: failed to open PCM near/out" that printed from scenario 1 was not an indication of a failure. Probably would be best to make the output more details so that it is clear.

Anyhow, yes, there actually is a problem with that code. There is nothing in there to lock the device from being opened by another process between closing the old stream and opening a new one.

Have a look at the field “lock” in struct audio_device, as well as functions “device_lock”, “device_try_lock”, and “device_unlock”.

Is scenario 3 like this?
apple <-- phonecall --> android <-- BT --> hikey960
I’m not sure what (if anything) is different between scenario 1 and 3, except that 3 worked and 1 did not.

Diagram of scenario 3 is the same as scenario 2. The difference is that in senario 2 , I dial number on android and accept the phone call on iPhone. In senario 3, I dial number on iPhone and accept the phone call on android.

Then it seems like the problem is that with the apple, there is something strange happening with respect to the in-band ringing, since in scenario 3, there will be no ringing.

Might be good to re-run scenario 2 with complete logging (no grep).

It may also be good to get a more complete log of scenario 1. My first guess is that it could be that something is unhappy about having its stream violently closed. Possibly the HAL crashed. I wonder if in-band ringing may not be present on your android phone, so the stream is opened by the ringtone. What Android version is that device running?

Decided to go in a different direction with the WebRTC integration. Instead of converting the HAL to C++, I added a wrapper for it.

I think its a lot cleaner this way;

OK, I re-run scenario 2 and accept the phone call on hikey, then it works fine.

For scenario 1, I got following messages without grep:

01-25 01:16:19.365  7237  8368 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  8379  8391 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.audio_flinger' died
01-25 01:16:19.365  7237  7755 W SoundTrigger: Sound trigger service died!
01-25 01:16:19.365  7237  7248 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.audio_policy' died
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.sound_trigger_hw' died
01-25 01:16:19.365  8379  8434 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7178  7215 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  7178  7178 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7358  7558 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7387  7407 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.366  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:19.366  7237  7318 E AudioService: Audioserver died.
01-25 01:16:19.869  7237  7318 E AudioService: Audioserver died.
01-25 01:16:20.368  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:20.371  7237  7318 E AudioService: Audioserver died.
01-25 01:16:20.698  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:20.699  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:20.874  7237  7318 E AudioService: Audioserver died.
01-25 01:16:21.371  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:21.374  7237  7318 E AudioService: Audioserver died.
01-25 01:16:21.877  7237  7318 E AudioService: Audioserver died.
01-25 01:16:22.373  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:22.380  7237  7318 E AudioService: Audioserver died.
01-25 01:16:22.694  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:22.695  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:22.883  7237  7318 E AudioService: Audioserver died.
01-25 01:16:23.376  7237  7237 W AudioSystem: AudioPolicyService not published, waiting...
01-25 01:16:23.386  7237  7318 E AudioService: Audioserver died.
01-25 01:16:23.877  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:23.888  7237  7318 E AudioService: Audioserver died.
01-25 01:16:24.389  7237  7318 E AudioService: Audioserver died.
01-25 01:16:24.688  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:24.688  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:24.878  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:24.892  7237  7318 E AudioService: Audioserver died.
01-25 01:16:25.395  7237  7318 E AudioService: Audioserver died.
01-25 01:16:25.879  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:25.899  7237  7318 E AudioService: Audioserver died.
01-25 01:16:26.401  7237  7318 E AudioService: Audioserver died.
01-25 01:16:26.834  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:26.834  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:26.880  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:26.904  7237  7318 E AudioService: Audioserver died.
01-25 01:16:27.870  7237  7249 I Telecom : Event: RecordEntry TC@1: REQUEST_DISCONNECT, null: ICA.dC(InCall package: com.android.car.dialer)@ADI
01-25 01:16:27.870  7237  7249 I Telecom : Call: Send disconnect to connection service for call: [TC@1, ACTIVE, com.android.bluetooth/.hfpclient.connserv.HfpClientConnectionService, tel:**********, A, childs(0), has_parent(false), [Capabilities: CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE], [Properties:]]: ICA.dC(InCall package: com.android.car.dialer)@ADI
01-25 01:16:27.405  7237  7318 E AudioService: Audioserver died.
01-25 01:16:27.871  8379  8379 D BluetoothHeadsetClient: terminateCall()
01-25 01:16:19.365  7237  8368 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  8379  8391 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.audio_flinger' died
01-25 01:16:19.365  7237  7755 W SoundTrigger: Sound trigger service died!
01-25 01:16:19.365  7237  7248 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.audio_policy' died
01-25 01:16:19.365  2098  2098 I ServiceManager: service 'media.sound_trigger_hw' died
01-25 01:16:19.365  8379  8434 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7178  7215 W AudioSystem: AudioFlinger server died!
01-25 01:16:19.365  7178  7178 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7358  7558 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.365  7387  7407 W AudioSystem: AudioPolicyService server died!
01-25 01:16:19.366  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:19.366  7237  7318 E AudioService: Audioserver died.
01-25 01:16:19.869  7237  7318 E AudioService: Audioserver died.
01-25 01:16:20.368  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:20.371  7237  7318 E AudioService: Audioserver died.
01-25 01:16:20.698  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:20.699  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:20.874  7237  7318 E AudioService: Audioserver died.
01-25 01:16:21.371  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:21.374  7237  7318 E AudioService: Audioserver died.
01-25 01:16:21.877  7237  7318 E AudioService: Audioserver died.
01-25 01:16:22.373  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:22.380  7237  7318 E AudioService: Audioserver died.
01-25 01:16:22.694  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:22.695  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:22.883  7237  7318 E AudioService: Audioserver died.
01-25 01:16:23.376  7237  7237 W AudioSystem: AudioPolicyService not published, waiting...
01-25 01:16:23.386  7237  7318 E AudioService: Audioserver died.
01-25 01:16:23.877  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:23.888  7237  7318 E AudioService: Audioserver died.
01-25 01:16:24.389  7237  7318 E AudioService: Audioserver died.
01-25 01:16:24.688  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:24.688  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:24.878  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:24.892  7237  7318 E AudioService: Audioserver died.
01-25 01:16:25.395  7237  7318 E AudioService: Audioserver died.
01-25 01:16:25.879  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:25.899  7237  7318 E AudioService: Audioserver died.
01-25 01:16:26.401  7237  7318 E AudioService: Audioserver died.
01-25 01:16:26.834  8379  8379 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-25 01:16:26.834  8379  8379 D HfpClientConnService: Finding block for device 60:45:CB:45:DC:50 blocks {60:45:CB:45:DC:50=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@399f24d}
01-25 01:16:26.880  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:26.904  7237  7318 E AudioService: Audioserver died.
01-25 01:16:27.870  7237  7249 I Telecom : Event: RecordEntry TC@1: REQUEST_DISCONNECT, null: ICA.dC(InCall package: com.android.car.dialer)@ADI
01-25 01:16:27.870  7237  7249 I Telecom : Call: Send disconnect to connection service for call: [TC@1, ACTIVE, com.android.bluetooth/.hfpclient.connserv.HfpClientConnectionService, tel:**********, A, childs(0), has_parent(false), [Capabilities: CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE], [Properties:]]: ICA.dC(InCall package: com.android.car.dialer)@ADI
01-25 01:16:27.405  7237  7318 E AudioService: Audioserver died.
01-25 01:16:27.871  8379  8379 D BluetoothHeadsetClient: terminateCall()
01-25 01:16:27.880  7237  7237 W AudioSystem: AudioPolicyService not published, waiting...
01-25 01:16:27.915  8379  8423 W HeadsetClientStateMachine: Unhandled AT OK StackEvent {type:EVENT_TYPE_CMD_RESULT, value1:0, value2:0, value3:0, value4:0, string: "null", device:60:45:CB:45:DC:50}
01-25 01:16:28.299  8379  8414 W bt_btif : bta_dm_pm_ssr: conn_srvc id:27, app_id:1
01-25 01:16:28.299  8379  8414 W bt_btif : bta_dm_pm_ssr: conn_srvc id:18, app_id:0
01-25 01:16:28.299  8379  8414 W bt_btif : bta_dm_pm_ssr: conn_srvc id:26, app_id:1
01-25 01:16:28.299  8379  8414 W bt_btif : bta_dm_pm_ssr ssr:2, lat:1200
01-25 01:16:28.300  8379  8423 I ServiceManager: Waiting for service media.audio_flinger...
01-25 01:16:28.381  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:29.301  8379  8423 I ServiceManager: Waiting for service media.audio_flinger...
01-25 01:16:29.386  7237  7237 I ServiceManager: Waiting for service media.audio_policy...
01-25 01:16:29.889  2171  2171 I VMS.NATIVE_LOOP: type=1400 audit(0.0:5030): avc: denied { search } for name="1508" dev="proc" ino=13314 scontext=u:r:vms:s0 tcontext=u:r:vendor_init:s0 tclass=dir permissive=1
01-25 01:16:30.303  8379  8423 I ServiceManager: Waiting for service media.audio_flinger...

Audioserver died. Maybe it is caused by closing existing stream procedure.
I’ll try to use existing stream instead of closing it.

That makes sense.
But reusing will lead to contention.

I wonder the root cause of my problem may be not about the USB sound card. Because using iPhone has no problem. My android phone runs android 6.0.1 and has no in-band ringing function. I tried to make it work today, but if I close the existing stream, the system will crash. It’ quite strange that the reason why it crash is because of a free() function call.
When I close the existing stream, I’ll call adev_close_output_stream()

static void adev_close_output_stream(struct audio_hw_device *hw_dev,
                                     struct audio_stream_out *stream)
{
    struct stream_out *out = (struct stream_out *)stream;
    ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);

    adev_remove_stream_from_list(out->adev, &out->list_node);

    /* Close the pcm device */
    out_standby(&(out->stream.common));

    free(out->conversion_buffer);

    out->conversion_buffer = NULL;
    out->conversion_buffer_size = 0;

    device_lock(out->adev);
    out->adev->device_sample_rate = 0;
    device_unlock(out->adev);
    
    //free(stream);
}

I have to mark the line “free(stream)” or it will cause the system to be crashed. It’s so strange, isn’t it?
And I also tried to use the existing stream instead of closing it , but I have no idea how to use it.
Maybe I should call the out_write() function? Because the existing stream was not created by pcm_open(), l can’t call pcm_write().

Its not strange at all. Calling free deallocates the memory and sets the pointer to 0, which will naturally impact the other process that thinks that it has an open stream. If that other process tries to write to a closed stream, you will obviously get a crash.

If your android device does not have in-band ringing, then the other process that is trying to write to the sound card will be trying to play the RING TONE.

Rather than just trying to take the stream away from the ring tone player, you would be better served in convincing the ring tone player that it STILL HAS a stream. You do this by altering the out_write function (as well as any other function that it tries to use on the stream) so that it will provide the expected return value, without trying to do something that it is unable to do.

Now as far as using pcm_write vs out_write… you would be best advised to understand the functions before you attempt to hack them. In the out_write function, you see that its real work is through a function “proxy_write”, and when you look at the proxy_write function (which you will find in system/media/alsa_utils/alsa_device_proxy.c), you will see that it just calls pcm_write.

The stream structure’s 6th field is an “alsa_device_proxy”.
This is an alsa_device_proxy:

typedef struct {
    alsa_device_profile* profile;

    struct pcm_config alsa_config;

    struct pcm * pcm;

    size_t frame_size;    /* valid after proxy_prepare(), the frame size in bytes */
    uint64_t transferred; /* the total frames transferred, not cleared on standby */
} alsa_device_proxy;

You will note that its 3rd field is a “pcm”, and a pcm can be written to using “pcm_write”.

1 Like

Thank you for detailed explanation.
I think I have to spend more time tracing source code.
What tools do you suggest to trace the source code?

‘grep’ is one of the best tools for finding your way through source code, especially with the “-n” and “-r” parameters.

I very strongly recommend against trying to re-use an existing stream, for two main reasons;

  1. If there is no existing stream,
  2. If there is an existing stream, but its parameters don’t match your needs, for instance, wrong sample rate, wrong channel count.

If I don’t re-use the existing stream,what solution do I have? Closing the existing steam will kill the system. Any other solution to resolve the problem?

If I mark ‘free(stream)’, there will be one successful phone call that I can hear sound from USB and speak into the mic. If I dial number again, the system will crash with an unknown reason.

There is no reason why you can’t close the input stream. You just need to be a lot more careful about how you manipulate it.

I’ve already explained that what you need to do is WHEN you close the stream, you need to manipulate the behavior or any and all functions that this will impact such that they behave in exactly the way they are expected to behave.

So for a more detailed explanation;

Add a new field to your stream_in and stream_out structures. This field will store a boolean value indicating that the stream is closed so that the hardware can be used by HFP.

When you are about to open your own streams, first mark the streams using that new field, then use pcm_close on the pcm’s associated with those streams (don’t close the stream, close the pcm).

You will also need to find EVERYWHERE in the HAL that actually uses pcm’s, and where it would access the pcm, instead just return the expected value but don’t actually let it try touching any pcm.

Once you close the SCO, you need to go through all of the streams that are still present, and RE-OPEN their PCMs – the alsa_device_proxy structure has a pcm_config as its second field.

Finally, if there is anything at all that attempts to OPEN a new stream while you have the SCO running, you need to mark that new stream, and skip the actual pcm_open.