This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

A3DP Multiroom Demo

Other Parts Discussed in Thread: TLV320AIC3262, TLV320AIC3262EVM-U, CC2564, CC256XQFNEM

Hi, I'm testing the A3DP Multiroom Demo, my plan is to use an headset as a slave and a tiva-19x as master. I connect the tiva to the headset issuing master-addr and then I connect my phone to the tiva and start the stream. All the logs look correct but I can't hear any sound out of my headset (BT0029 -> http://www.amazon.de/LogiLink-BT0029-bluetooth-V3-0-Headset/dp/B00BG23GSE). 

 

  • Hi,

    Does it happen with other headsets or only this one?
    Is it possible to share the air sniffer logs?

    Regards,
    Gigi Joseph.
  • Thanks for the answer, I'm starting thinking too it is a headset related problem.

    • Coud you please confirm that the demo is supposed to work with any sink that support a2dp?

    I'll get a new headset in the next days and I'll let you know how it goes.

    Thanks again for the fast support.

  • Hi,

    AFAIK, there are no limitations. Please let me know how it goes with another A2DP sink device.

    Regards,
    Gigi Joseph.
  • Hi I am back. I tried the a3dpMultiRoomDemo with my new headset (M70) with no availl. I do as follow:

    1. Set name..
    2. Set class..
    3. Master headsetaddress 

    A3DP+SNK>Master 0CE0E476AF37 
    A3DP+SNK>Connected to 0x0ce0e476af37 (1). 
    Enabling multi-room mode on the slave...

    Then I connect my phone and start the streaming

    A3P+SNK>
    etAUD_Stream_State_Change_Indication
    BD_ADDR: 0x2c2997df8074
    StreamState: Started

    But I can hear nothing from the headset. I think the problem is with the connection between the board and the headset since if I connect the smartphone to the headset I can hear an aknowledge while if I connect the board to the headset I hear nothing. Do you have any idea?

  • Roberto,

    The A3DP multiroom feature is TI-proprietary. Commercial-off-the-shelf devices don't support it. It's purpose is to allow one source to play to multiple sinks without the source having to know about the second sink. An example use case would be 2 Bluetooth speakers in the same room. When the user connects to one speaker the audio will automatically play out of both.

    Sounds like you want to use the Tiva as an A2DP "repeater". You can do this by using the A2DPDemo app as a starting point. The app supports use of sink or source mutually exclusively, it will need to be modified to support both source and sink simultaneously.

    I think the following will work for you:

    1. When you receive the etAUD_Stream_Open_Indication event then it means a source has connected to the Tiva.

    2. In the callback function call AUD_Open_Remote_Stream(BluetoothStackID, <Headset_Device_Address>, astSRC).

    3. The etAUD_Stream_Open_Confirmation event is dispatched when the connection procedure is complete. Check the OpenStatus variable to see if the connection is successful, 0 is success.

    4. When the etAUD_Encoded_Audio_Data_Indication event is received then just send the audio to the headset with AUD_Send_Encoded_Audio_Data().

    There is one issue with step 4. When AUD connects to the headset it will choose the best-fit audio configuration. When the source connected to the Tiva it used its best-fit audio configuration. The 2 configurations may not match. I suspect this might not be an issue unless the bitpool in the source to Tiva connection is higher than the bitpool in the Tiva to headset connection. The reason I say it might not be an issue is because the SBC configuration is sent in every packet in every SBC frame, even if it doesn't match the initial configuration the decoder on the sink should still be able to decode the audio.

    If this is an issue there are a few options to workaround:

    1. If the bitpool is the problem then the max bitpool can be lowered on the Tiva with the AUD_Change_Media_Codec_Parameters() function.

    2. You could decode every packet received and re-encode it before its sent out. This would work, but you'll lose audio quality plus spend time decoding and encoding the audio. Not sure the Tiva will be able to do this in real-time.

    3. Use the GAVD API for the Tiva to headset connection and use the same configuration as the source to Tiva connection. AUD will still be useful for handling AVRCP connections in this case.

    Thanks,
    Samuel
  • Thanks for all your help Samuel, I'll give it a try and I'll let you know how it goes in a couple of days.
  • Hi Samuel, I got a question.

    Since I don't have/don't need (do I?) an external codec connected to my board I commented the line were the a2dp Demo tried to set up the SoundInit(). I then launched the demo and tried the source and sink modes to see if the board was discoverable but with no avail (I did the other things suggested in the wiki aka SetClass SetLocalName..). I don't seem to be able to see my board from a phone. Am I missing something?
  • Roberto,

    Are you trying to discover the Tiva with an iOS device? If so you need to set the class of device in addition to being discoverable. iOS devices only show devices in which the other device has a class of device which it cares about, i.e. it only shows devices that appear, at first glance, to have services that it can use.

    You can use a class of device of 0x040424 and the SetClassOfDevice of command, for example:

    SetClassOfDevice 0x040424

    Thanks,
    Samuel

  • I'm using a WP but I've already tried the set class since WP has similar problems. The only difference between the original demo and mine is that I removed the SoundInit call.

    This is my output:

  • Roberto,

    When you restore the call to SoundInit() can you discover the Tiva board?

    Thanks,
    Samuel
  • Can't test the call, since I have no external audio codec and the call will faill. I just tried the multiroom demo and it can see my board nicely.
  • Roberto,

    Looking into it. You should be able to drop in Main.c from A3DPMultiRoomDemo in the meantime. The differences between the 2 are minor, but there is no SoundInit() call in the multi-room demo. I also see that there is a call to PinoutSet() in the A2DPDemo version of Main.c. This call is used to initialize the pinouts for the demo when a codec is attached. Please be sure to remove this in addition to SoundInit() in the version of Main.c that you use.
     
    Thanks,
    Samuel

  • Thanks Samuel,
    I'll try to mod that with my changes, will let you know how it goes.
  • Roberto,

    A2DPDemo was verified with the TLV320AIC3262 audio codec using the TLV320AIC3262EVM-U EVM. The SoundInit() call in the app assumes that the TLV320AIC3262EVM-U EVM is connected to the Tiva board and tries to initialize the TLV320AIC3262 audio codec.

    As expected there's not an audio codec on the Tiva board.

    Hope this helps.

    Thanks,
    Samuel

  • Thanks Samuel, I already knew the tiva didn't have a codec, I didn't expect removing soundinit would affect the discoverability of the whole demo.

    I need a couple of weeks to do another job, I should be able to reasume working on it around June 25. Btw I'm following your suggestion using the other demo and I was able to connect with both the phone and one headset not concurrently, when the headset is connected the aud procedure that try to connect with the phone return an error (-518 if I'm not mistaken). 

    I'l do some testing and try a workaround by the end of the month and then I'll write back here to let you know, thanks again.

  • Hi, I'm back to work!

    I'm still trying to make my "repeater" configuration work, I got a few questios.

    1. When I try to connect to the headset using my smart phone, the headset tells me that he is connected with a smartphone while when I connect the tiva to the headset using AUD_Open_Remote_Stream(BluetoothStackID, Headset_Device_Address1, astSRC); it only tells me that he is connected, do you have any idea why?

    2. I followed your suggestions, this summarize the actions I perform:
    • ret_val = AUD_Initialize(BluetoothStackID, &InitializationInfo, AUD_Event_Callback, 0); 
    • I then wait for etaud_stream_open_indication()
    •  
    • I connect the smartphone to the tiva, the tiva receives etaud_stream_open_indication
    •  
    • The tiva sends: aud_open_remote_stream(...,Headset_Device_Address1,..);
    •  
    • The tiva receive etaud_Stream__open_confirmation
    •  
    • Smartphone start streaming music
    • The tiva receive etaud_encoded_audio_data_indication
    •  
    • Then i use aud_send_encoded_audio_Data
    •  
    • It faills telling me that the stream to the headset is NOT ACTIVE

    I'm using A3DP MultiRoomDemo as base, i removed all the call to a3dp procedures. 

    The smartphone begin the procedure...

    Smartphone start streaming

  • Ok now "it works" I still have to work with the bitpoll since it saturate the buffer too quickly. The problem was that I didn't change the stream state of the headset.
  • So, I made many trials but I don't seem to be able to make the connection work using aud api. I'm stucked trying to send audio to one headset. The phone and the headset connect successfully to the tiva, then I start sending the data the tiva receive from the phone to the headset, I hear stuttering music for a couple of seconds at most then nothing, if I stop for a couple of seconds and then restart the communication I hear again a couple of seconds of music and so on...

    The send data procedure doesn't return any error,  I tried to cap the bitpool to 33, to reduce the mtu, to define AudioSRCSupportedFormats as follow all with no avail.

    define TONE_SAMPLES_PER_SECOND   44100
    static AUD_Stream_Format_t AudioSRCSupportedFormats[] =
    {
      { TONE_SAMPLES_PER_SECOND, 2, 0 }
    };
    #define NUM_SRC_SUPPORTED_FORMATS      (sizeof(AudioSRCSupportedFormats)/sizeof(AUD_Stream_Format_t))

    If you have any idea I'm open, in the meantime I'll try to switch to the gavd api and make them works.

  • Roberto,

    You can print the SBC configuration in the etAUD_Stream_Open_Indication and etAUD_Stream_Open_Confirmation when Status == 0 events by calling AUD_Query_Stream_Configuration(). For example:

    AUD_Stream_Configuration_t StreamConfiguration;
    
    if(AUD_Query_Stream_Configuration(BluetoothStackID, EventInfo->BD_ADDR, LocalStreamType, &StreamConfiguration) == 0)
    {
       Display(("Codec Type:         %d\r\n", StreamConfiguration.MediaCodecType));
       Display(("Codec Info Length:  %d\r\n", StreamConfiguration.MediaCodecInfoLength));
       Display(("Sampling Frequency: %d\r\n", A2DP_SBC_READ_SAMPLING_FREQUENCY(StreamConfiguration.MediaCodecInformation)));
       Display(("Channel Mode:       %d\r\n", A2DP_SBC_READ_CHANNEL_MODE(StreamConfiguration.MediaCodecInformation)));
       Display(("Block Length:       %d\r\n", A2DP_SBC_READ_BLOCK_LENGTH(StreamConfiguration.MediaCodecInformation)));
       Display(("Subbands:           %d\r\n", A2DP_SBC_READ_SUBBANDS(StreamConfiguration.MediaCodecInformation)));
       Display(("Allocation Method:  %d\r\n", A2DP_SBC_ASSIGN_ALLOCATION_METHOD(StreamConfiguration.MediaCodecInformation)));
       Display(("Min Bitpool:        %d\r\n", A2DP_SBC_READ_MINIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
       Display(("Max Bitpool:        %d\r\n", A2DP_SBC_READ_MAXIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
    }

    You can determine the meaning of the values using the constants in A2DPAPI.h, for example A2DP_SBC_SAMPLING_FREQUENCY_44_1_KHZ_VALUE, A2DP_SBC_SAMPLING_FREQUENCY_48_KHZ_VALUE, A2DP_SBC_CHANNEL_MODE_MONO_VALUE, A2DP_SBC_CHANNEL_MODE_DUAL_CHANNEL_VALUE, etc. Or you can refer to the A2DP specification.

    I think you are going to see that there is a mismatch in the configuration between the 2 devices. If this is the case then there are 2 options:

    1) Decode the audio, optionally upsample or downsample it, and re-encode in real-time. There will be audio quality loss with this method. The Tiva may have not the resources to do this in real-time.

    2) Use the GAVD API. To make it simpler on the user AUD doesn't allow tight control of the audio capabilities, in this case you need that low-level control so that both devices have matching configurations. In your application which device connects to Tiva first, the source or headset? If the source connects first then you can connect to the headset with the same configuration. If the headset connects first you can create an endpoint that mirrors the capabilities (not configuration, you'll violate the spec) of the headset. Let me know what your use case is and I can provide more details on this point. I would refer to the WiLink 8 Linux SDK (LINUXEZSDK-WILINK8-BT at http://www.ti.com/tool/wilink-swfor GAVD example code. There are 2 useful apps there, LinuxAVRGAV and LinuxGAV. LinuxAVRGAV demos using AVRCP and GAVD together, LinuxGAV demos using GAVD alone.

    Samuel

  • Hi Samuel,

    • "You can print the SBC configuration in the etAUD_Stream_Open_Indication and etAUD_Stream_Open_Confirmation when Status == 0 events by calling AUD_Query_Stream_Configuration(). For example"

    Tomorrow as soon as I get to work I'll print the SBC configuration to confirm that.

    • "Decode the audio, optionally upsample or downsample it, and re-encode in real-time. There will be audio quality loss with this method. The Tiva may have not the resources to do this in real-time."

    I prefer not to consider this option.

    • "Use the GAVD API. To make it simpler on the user AUD doesn't allow tight control of the audio capabilities, in this case you need that low-level control so that both devices have matching configurations. In your application which device connects to Tiva first, the source or headset? If the source connects first then you can connect to the headset with the same configuration. If the headset connects first you can create an endpoint that mirrors the capabilities (not configuration, you'll violate the spec) of the headset. Let me know what your use case is and I can provide more details on this point. I would refer to the WiLink 8 Linux SDK (LINUXEZSDK-WILINK8-BT at http://www.ti.com/tool/wilink-swfor GAVD example code. There are 2 useful apps there, LinuxAVRGAV and LinuxGAV. LinuxAVRGAV demos using AVRCP and GAVD together, LinuxGAV demos using GAVD alone."

    In my application the source connect first (since I used the aud_api I will need to rewrite both sides using the gavd-api am I right?) but it is not mandatory if following other courses could smooth things,  I'll check the example code you linked and update you by tomorrow this hour.

    Thanks again, keep the good work.

  • Roberto,

    I don't think you can use AUD and GAVD together because AUD registers for signaling events with GAVD_Register_Signalling_Connection_Status(), the app won't be able to register for signaling events. When AUD sees a signaling connection it will try to discover the remote device's endpoints in order to connect to an endpoint. When AUD sees that it doesn't have any source endpoints to match the sink's endpoints it will disconnect the signalling connection and you'll lose the connection to the device.

    Samuel

  • So here are the prints of the codecs configuration:

    Source

    • Codec Type: 0
    • Codec Info Length: 4
    • Sampling Frequency: 32
    • Channel Mode: 1
    • Block Length: 16
    • Subbands: 4
    • Allocation Method: 1
    • Min Bitpool: 10
    • Max Bitpool: 53

    Headset1

    • Codec Type: 0
    • Codec Info Length: 4
    • Sampling Frequency: 32
    • Channel Mode: 1
    • Block Length: 16
    • Subbands: 4
    • Allocation Method: 1
    • Min Bitpool: 10
    • Max Bitpool: 53

    I can't see any differences...

    I'll now start working with GAVD.API, I'll update you soon.

  • Roberto,

    If there aren't any differences using GAVD isn't going to fix this problem. Did you start the stream on the headset with AUD_Change_Stream_State()? Does the headset sound okay if you use the source device only and don't use Tiva at all?

    I believe you are still going to have to use GAVD to achieve what you want regardless.

    Thanks,
    Samuel

    • Yes I started the stream using AUD_Change_Stream_State (and I receive etAUD_Stream_State_Change_Confirmation from the headset), I can hear stuttering music for just a couple of seconds then nothing with no error from the api call.
    • Yes using the source directly the headset works fine.

    I called

    In etAUD_Stream_Open_Confirmation:

     if(AUD_Query_Stream_Configuration(BluetoothStackID, AUD_Event_Data->Event_Data.AUD_Stream_Open_Confirmation_Data->BD_ADDR, astSRC, &StreamConfiguration) == 0)

    And in etAUD_Stream_Open_Indication:

    if(AUD_Query_Stream_Configuration(BluetoothStackID, AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR, astSNK, &StreamConfiguration) == 0)

    I'll post a snipet of my relevant code maybe there is some conceptual error I can't see, there are just 3 procedures tell me if you need more info:

    static BTPSCONST AUD_Stream_Format_t AudioSNKSupportedFormats[] =
    {
       { 44100, 2, 0 },
       { 48000, 2, 0 },
       { 48000, 1, 0 },
       { 44100, 1, 0 }
    } ;
    #define NUM_SNK_SUPPORTED_FORMATS                     (sizeof(AudioSNKSupportedFormats)/sizeof(AUD_Stream_Format_t))
    
    
    #define TONE_SAMPLES_PER_SECOND   44100
    static AUD_Stream_Format_t AudioSRCSupportedFormats[] =
    {
      { TONE_SAMPLES_PER_SECOND, 2, 0 }
    };
    #define NUM_SRC_SUPPORTED_FORMATS      (sizeof(AudioSRCSupportedFormats)/sizeof(AUD_Stream_Format_t))
    
    
    
    
    
    static int Sink_SourceMode(ParameterList_t *TempParam)
    {
    	int Result;
    	Result = Initialize_Source_Sink();
    
    	//StrToBD_ADDR("0CE0E476AF37", &Headset_Device_Address1);
    	StrToBD_ADDR("0CE0E47fAB66", &Headset_Device_Address1);
    	if(!Result)
    	{
    		Display(("Sink_Source inizializzato.\r\n"));
    		if((!SetDisc()) && (!SetConnect()) && (!SetPairable()))
    		{
    			Display(("TIVA is DISC_CONN_PAIR.\r\n"));
    		}
    		else
    		{
    			Display(("Could not set up pairing/connectability/discoverability.\r\n"));
    			Result = FUNCTION_ERROR;
    			return(Result);
    		}
    
    	}
    	else
    	{
    		DisplayFunctionError("Initialize_Sink_Source()", Result);
    		Result = EXIT_CODE;
    		return(Result);
    	}
    	return(Result);
    }
    
    
    
    static int Initialize_Source_Sink(void)
    {
    	   int ret_val;
    
    	   AUD_Initialization_Info_t                InitializationInfo;
    	   AUD_Stream_Initialization_Info_t         InitializationInfoSRC;
    	   AUD_Stream_Initialization_Info_t         InitializationInfoSNK;
    	   AUD_Remote_Control_Initialization_Info_t InitializationInfoAVR;
    	   AUD_Remote_Control_Role_Info_t           RemoteControlRoleInfo;
    
    	  /* First, check to make sure that a valid Bluetooth Stack ID exists. */
    	  if(BluetoothStackID)
    	  {
    		 /* Next, check to make sure that the Audio Manager has not already*/
    		 /* been initialized.                                              */
    		 if(!Initialized) 
    		 { 
    			/* Set up our stream configuration parameters.                 */
    			InitializationInfoSRC.InitializationFlags          = 0;
    			InitializationInfoSRC.NumberConcurrentStreams      = 1;
    			InitializationInfoSRC.EndpointSDPDescription       = "A2DP Source";
    			InitializationInfoSRC.NumberSupportedStreamFormats = NUM_SRC_SUPPORTED_FORMATS;
    
    			/* Set up our stream configuration parameters. 					*/
    			InitializationInfoSNK.InitializationFlags          = 0;
    			InitializationInfoSNK.NumberConcurrentStreams      = 1;
    			InitializationInfoSNK.EndpointSDPDescription       = "A2DP Sink";
    			InitializationInfoSNK.NumberSupportedStreamFormats = NUM_SNK_SUPPORTED_FORMATS;
    
    			/* Initialize the stream configuration supported format list.  */
    			BTPS_MemCopy(InitializationInfoSRC.StreamFormat, AudioSRCSupportedFormats, sizeof(AudioSRCSupportedFormats));
    
    			/* Initialize the stream configuration supported format list.  */
    			BTPS_MemCopy(InitializationInfoSNK.StreamFormat, AudioSNKSupportedFormats, sizeof(AudioSNKSupportedFormats));
    
    
    			/* Set up the remote control role configuration.               */
    			RemoteControlRoleInfo.SupportedFeaturesFlags       = SDP_AVRCP_SUPPORTED_FEATURES_CONTROLLER_CATEGORY_1;
    			RemoteControlRoleInfo.ProviderName                 = "Stonestreet One";
    			RemoteControlRoleInfo.ServiceName                  = "A2DP Source and Sink";
    
    			/* Set up the remaining AVRCP Controller configuration.        */
    			InitializationInfoAVR.InitializationFlags          = 0;
    			InitializationInfoAVR.TargetRoleInfo               = &RemoteControlRoleInfo;
    			InitializationInfoAVR.ControllerRoleInfo           = &RemoteControlRoleInfo;
    			InitializationInfoAVR.SupportedVersion             = apvVersion1_0;
    
    
    			/* Set up the rest of the AUD initialization data.             */
    			InitializationInfo.InitializationFlags             = AUD_INITIALIZATION_INFO_FLAGS_OVERRIDE_MEDIA_MTU; // I tried with 0 too
    			InitializationInfo.RemoteControlInitializationInfo = &InitializationInfoAVR;
    			InitializationInfo.SRCInitializationInfo           = &InitializationInfoSRC; 
    			InitializationInfo.SNKInitializationInfo           = &InitializationInfoSNK;
    			InitializationInfo.MediaMTU                        = 875; //Commented if flags = 0
    
    			/* Everything has been initialized, now attempt to initialize  */
    			/* the Audio Manager.  */
    			 Display(("Inizializzo AUD\r\n"));
    			 ret_val = AUD_Initialize(BluetoothStackID, &InitializationInfo, AUD_Event_Callback, 0);
    	         if(!ret_val)
    	         {
    	            DisplayFunctionSuccess("AUD_Initialize() Source_Sink");
    	            Initialized = TRUE;
    	            //ret_val = AUD_Change_Media_Codec_Parameters(BluetoothStackID, astSRC, 0x51, 0x51);
    	            ret_val = AUD_Change_Media_Codec_Parameters(BluetoothStackID, astSNK, 10, 53);
    	            ret_val = AUD_Change_Media_Codec_Parameters(BluetoothStackID, astSRC, 10, 53);
    	            if(!ret_val)
    	            	Display(("Bitpool changed\r\n"));
    	            else
    	            {
    	            	Display(("Bitpool change faillure\r\n"));
    	            	return -1;
    	            }
    	         }
    	         else
    	         {
    	            Display(("Errore AUD_Initialize()"));
    	            return -1;
    	         }
    
    	      }
    	      else
    	      {
    	    	  Display(("Aud already initializated"));
    		 	  return -1;
    	      }
    	   }
    	   else
    	   {
    		   Display(("BluetoothStackID doesn't exist yet"));
    		   return -1;
    	   }
           return ret_val; //ret_val == 0
    }
    
    
    
    
    
    static void BTPSAPI AUD_Event_Callback(unsigned int BluetoothStackID, AUD_Event_Data_t *AUD_Event_Data, unsigned long CallbackParameter)
    {
       AUD_Stream_Configuration_t StreamConfiguration;
       if((BluetoothStackID) && (AUD_Event_Data))
       {
          switch(AUD_Event_Data->Event_Data_Type)
          {
             case etAUD_Open_Request_Indication:
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Open_Request_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Open_Request_Indication\r\n"));
                Display(("BD_ADDR:               %s\r\n", Callback_BoardStr));
                break;
    
    
             case etAUD_Stream_Open_Indication:
                /* Occurs whenever the master device connects out to us.    */
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Stream_Open_Indication\r\n"));
                Display(("BD_ADDR:     %s\r\n", Callback_BoardStr));
    
                if(AUD_Query_Stream_Configuration(BluetoothStackID, AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR, astSNK, &StreamConfiguration) == 0)
                {
    				Display(("\r\n"));
    				Display(("\r\n"));
    				Display(("\r\n"));
    				Display(("\r\n"));
    				Display(("Codec Type:         %d\r\n", StreamConfiguration.MediaCodecType));
    				Display(("Codec Info Length:  %d\r\n", StreamConfiguration.MediaCodecInfoLength));
    				Display(("Sampling Frequency: %d\r\n", A2DP_SBC_READ_SAMPLING_FREQUENCY(StreamConfiguration.MediaCodecInformation)));
    				Display(("Channel Mode:       %d\r\n", A2DP_SBC_READ_CHANNEL_MODE(StreamConfiguration.MediaCodecInformation)));
    				Display(("Block Length:       %d\r\n", A2DP_SBC_READ_BLOCK_LENGTH(StreamConfiguration.MediaCodecInformation)));
    				Display(("Subbands:           %d\r\n", A2DP_SBC_READ_SUBBANDS(StreamConfiguration.MediaCodecInformation)));
    				Display(("Allocation Method:  %d\r\n", A2DP_SBC_READ_ALLOCATION_METHOD(StreamConfiguration.MediaCodecInformation)));
    				Display(("Min Bitpool:        %d\r\n", A2DP_SBC_READ_MINIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
    				Display(("Max Bitpool:        %d\r\n", A2DP_SBC_READ_MAXIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
    				Display(("\r\n"));
    				Display(("\r\n"));
    				Display(("\r\n"));
    				Display(("\r\n"));
                }
                else
    				Display(("Query 1 fallita\r\n"));
    
    
    
    
                /* Set this BD_ADDR as being active, and set up the stream. */
                A2DPRemoteBD_ADDR = AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR;
                //OpenA3DPStream(AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->BD_ADDR);
    
    
    
                Display(("Master MTU: %d\r\n", AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->MediaMTU));
    
    			Display(("Master Sample frequency: %d\r\n", AUD_Event_Data->Event_Data.AUD_Stream_Open_Indication_Data->StreamFormat.SampleFrequency));
    
    
                Display(("Tento di collegarmi ad H1.\r\n"));
    			Result= AUD_Open_Remote_Stream(BluetoothStackID, Headset_Device_Address1, astSRC);
    			if(!Result)
    			{
    				Display(("Aud_Open_Remote_Stream lanciato verso h1 \r\n"));
    				Display(("In attesa di etAUD_Stream_Open_Confirmation\r\n"));
    			}
    			else
    			{
    				Display(("ERRORE Aud_Open_Remote_Stream verso h1 fallito, indaga \r\n"));
    			}
    			//---> DEVE ARRIVARE etAUD_Stream_Open_Confirmation da h1
                break;
    
             case etAUD_Stream_Open_Confirmation:
    			Display(("etAUD_Stream_Open_Confirmation\r\n"));
    
    			if(COMPARE_BD_ADDR(AUD_Event_Data->Event_Data.AUD_Stream_Open_Confirmation_Data->BD_ADDR, Headset_Device_Address1))
    			{
    				Display(("H1 anwers with OpenStatus:     %d\r\n", AUD_Event_Data->Event_Data.AUD_Stream_Open_Confirmation_Data->OpenStatus));
    				if(AUD_Event_Data->Event_Data.AUD_Stream_Open_Confirmation_Data->OpenStatus == AUD_STREAM_OPEN_CONFIRMATION_STATUS_SUCCESS)
    				{
    					Display(("Aud_Open_Remote_Stream confirmed from h1\r\n"));
    					Connection = TRUE;
    
    
    					if(AUD_Query_Stream_Configuration(BluetoothStackID, AUD_Event_Data->Event_Data.AUD_Stream_Open_Confirmation_Data->BD_ADDR, astSRC, &StreamConfiguration) == 0)
    					{
    						Display(("\r\n"));
    						Display(("\r\n"));
    						Display(("\r\n"));
    						Display(("\r\n"));
    					   Display(("Codec Type:         %d\r\n", StreamConfiguration.MediaCodecType));
    					   Display(("Codec Info Length:  %d\r\n", StreamConfiguration.MediaCodecInfoLength));
    					   Display(("Sampling Frequency: %d\r\n", A2DP_SBC_READ_SAMPLING_FREQUENCY(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Channel Mode:       %d\r\n", A2DP_SBC_READ_CHANNEL_MODE(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Block Length:       %d\r\n", A2DP_SBC_READ_BLOCK_LENGTH(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Subbands:           %d\r\n", A2DP_SBC_READ_SUBBANDS(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Allocation Method:  %d\r\n", A2DP_SBC_READ_ALLOCATION_METHOD(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Min Bitpool:        %d\r\n", A2DP_SBC_READ_MINIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
    					   Display(("Max Bitpool:        %d\r\n", A2DP_SBC_READ_MAXIMUM_BIT_POOL_VALUE(StreamConfiguration.MediaCodecInformation)));
    						Display(("\r\n"));
    						Display(("\r\n"));
    						Display(("\r\n"));
    					}
    					else
    						Display(("QUERY Failed\r\n"));
    
    				}
    				else
    					Display(("etAUD_Stream_Open_Confirmation not confirmed \r\n"));
    			}
    			else
    				Display(("Error\r\n"));
    
                /* Turn off discoverability and connectability to improve   */
                /* the multiroom throughput behavior.                       */
                GAP_Set_Discoverability_Mode(BluetoothStackID, dmNonDiscoverableMode, 0);
                GAP_Set_Connectability_Mode(BluetoothStackID, cmNonConnectableMode);
    
    			Display(("State change H1\r\n"));
    			//stream activation
    			Result = AUD_Change_Stream_State(BluetoothStackID, Headset_Device_Address1, astSRC , astStreamStarted);
    			switch(Result)
    			{
    				case 0:
    					Display((" AUD_Change_Stream_State Succes_ID\r\n"));
    				break;
    				case BTAUD_ERROR_INVALID_BLUETOOTH_STACK_ID:
    					Display(("ERROR_INVALID_BLUETOOTH_STACK_ID\r\n"));
    				break;
    				case BTAUD_ERROR_NOT_INITIALIZED:
    					Display(("BTAUD_ERROR_NOT_INITIALIZED\r\n"));
    				break;
    				case BTAUD_ERROR_INVALID_OPERATION:
    					Display(("BTAUD_ERROR_INVALID_OPERATION\r\n"));
    				break;
    				case BTAUD_ERROR_STREAM_NOT_CONNECTED:
    					Display(("BTAUD_ERROR_STREAM_NOT_CONNECTED\r\n"));
    				break;
    				case BTAUD_ERROR_STREAM_NOT_INITIALIZED:
    					Display(("BTAUD_ERROR_STREAM_NOT_INITIALIZED\r\n"));
    				break;
    				case BTAUD_ERROR_STREAM_STATE_CHANGE_IN_PROGRESS:
    					Display(("BTAUD_ERROR_STREAM_STATE_CHANGE_IN_PROGRESS\r\n"));
    				break;
    				case BTAUD_ERROR_STREAM_FORMAT_CHANGE_IN_PROGRESS:
    					Display(("BTAUD_ERROR_STREAM_FORMAT_CHANGE_IN_PROGRESS\r\n"));
    				break;
    				case BTAUD_ERROR_STREAM_STATE_ALREADY_CURRENT:
    					Display(("BTAUD_ERROR_STREAM_STATE_ALREADY_CURRENT\r\n"));
    				break;
    				case BTAUD_ERROR_UNABLE_TO_CHANGE_STREAM_STATE:
    					Display(("BTAUD_ERROR_UNABLE_TO_CHANGE_STREAM_STATE\r\n"));
    				break;
    			}
    
    			//waiting headset --> etAUD_Stream_State_Change_Confirmation
    			//waiting board --> etAUD_Encoded_Audio_Data_Indication
    			break;
    
    
    
    		case etAUD_Stream_State_Change_Confirmation:
    			BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Stream_State_Change_Indication_Data->BD_ADDR, Callback_BoardStr);
    			/* Called whenever the master performs play/stop.           */
    			Display(("etAUD_Stream_State_Change_Indication\r\n"));
    			Display(("BD_ADDR:     %s\r\n", Callback_BoardStr));
      			if(AUD_Event_Data->Event_Data.AUD_Stream_State_Change_Confirmation_Data->Successful)
      			{
      				Display(("Headset confirmed stream activation\r\n"));
      				H1activationconfirmed = TRUE;
      			}
      			else
      			{
      				Display(("Headset stream activation faillure\r\n"));
      				H1activationconfirmed = FALSE;
      			}
    
    			break;
    
    
    			case etAUD_Encoded_Audio_Data_Indication:
    			if(Connection && H1activationconfirmed) 
    			{
    
    
    					Result = AUD_Send_Encoded_Audio_Data(BluetoothStackID,Headset_Device_Address1, AUD_Event_Data->Event_Data.AUD_Encoded_Audio_Data_Indication_Data->RawAudioDataFrameLength,
    							AUD_Event_Data->Event_Data.AUD_Encoded_Audio_Data_Indication_Data->RawAudioDataFrame);
    							Display(("Sent..\r\n"));
    				if(Result != 0)
    				{
    					if(Result == BTAUD_ERROR_INVALID_PARAMETER )
    					Display(("BTAUD_ERROR_INVALID_PARAMETER\r\n"));
    					if(Result == BTAUD_ERROR_INVALID_BLUETOOTH_STACK_ID)
    					Display(("BTAUD_ERROR_INVALID_BLUETOOTH_STACK_ID\r\n"));
    					if(Result == BTAUD_ERROR_NOT_INITIALIZED)
    					Display(("BTAUD_ERROR_NOT_INITIALIZED\r\n"));
    					if(Result == BTAUD_ERROR_INVALID_OPERATION)
    					Display(("BTAUD_ERROR_INVALID_OPERATION\r\n"));
    					if(Result == BTAUD_ERROR_STREAM_NOT_INITIALIZED)
    					Display(("BTAUD_ERROR_STREAM_NOT_INITIALIZED\r\n"));
    					if(Result == BTAUD_ERROR_STREAM_NOT_CONNECTED)
    					Display(("BTAUD_ERROR_STREAM_NOT_CONNECTED\r\n"));
    					if(Result == BTAUD_ERROR_STREAM_IS_NOT_ACTIVE)
    					Display(("BTAUD_ERROR_STREAM_IS_NOT_ACTIVE\r\n"));
    					if(Result == BTAUD_ERROR_UNABLE_TO_SEND_STREAM_DATA )
    					Display(("BTAUD_ERROR_UNABLE_TO_SEND_STREAM_DATA\r\n"));
    				}
    
    			}
    			else
    				Display(("Connection && H1activationconfirmed not true\r\n"));
               break;
    
    
    
    
    
    
             case etAUD_Stream_Close_Indication:
            	Display(("etAUD_Stream_Close_Indication NON e' controllato\r\n"));
                /* Occurs when the master either closes or disconnects.     */
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Stream_Close_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Stream_Close_Indication\r\n"));
                Display(("BD_ADDR:          %s\r\n", Callback_BoardStr));
    
                if(COMPARE_BD_ADDR(AUD_Event_Data->Event_Data.AUD_Stream_Close_Indication_Data->BD_ADDR, A2DPRemoteBD_ADDR))
                {
                   /* Check to see if this was a requested disconnect.      */
                   if(AUD_Event_Data->Event_Data.AUD_Stream_Close_Indication_Data->DisconnectReason == adrRemoteDeviceDisconnect)
                   {
                      /* Close the stream normally.                         */
                      ASSIGN_BD_ADDR(A2DPRemoteBD_ADDR, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
                      CloseA3DPStream();
                   }
                   else
                   {
                      /* On link loss or timeout, the A3DP API seems to     */
                      /* return invalid connection handle error codes if we */
                      /* try to close the stream. So, instead we will       */
                      /* manually reset the state here.                     */
                      Display(("Resetting A3DP stream state.\r\n"));
                      A3DPOpened  = FALSE;
                      A3DPPlaying = FALSE;
                   }
    
                   /* Flag that the stream is stopped.                      */
                   StreamState = ssStopped;
                }
    
                /* Since this demo only supports one AUD stream, we can     */
                /* safely assume this event means there are no more sources */
                /* connected, so reenable connectability/discoverability.   */
                SetConnect();
    
                if(ApplicationState == asMaster)
                   SetDisc();
    
                break;
    
    
    
             case etAUD_Remote_Control_Open_Indication:
            	Display(("etAUD_Remote_Control_Open_Indication NON e' controllato\r\n"));  //still to check
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Remote_Control_Open_Indication_Data->BD_ADDR, Callback_BoardStr);
    
                Display(("etAUD_Remote_Control_Open_Indication\r\n"));
                Display(("BD_ADDR:     %s\r\n", Callback_BoardStr));
    
                /* Change the stream state appropriately.                   */
                StreamState = A3DPPlaying?ssStarted:ssStopped;
                break;
    
    
    
             case etAUD_Remote_Control_Close_Indication:
            	Display(("etAUD_Remote_Control_Close_Indicatio NON e' controllato\r\n"));
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Remote_Control_Close_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Remote_Control_Close_Indication\r\n"));
                Display(("BD_ADDR:          %s\r\n", Callback_BoardStr));
                Display(("DisconnectReason: %d\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Close_Indication_Data->DisconnectReason));
    
                /* Change the stream state appropriately.                   */
                StreamState = A3DPPlaying?ssStarted:ssStopped;
                break;
    
    
             case etAUD_Remote_Control_Command_Indication:
            	 Display(("etAUD_Remote_Control_Command_Indication NON e' controllato\r\n"));
                break;
    
    
    
    
             case etAUD_Stream_Format_Change_Indication:
             	Display(("etAUD_Stream_Format_Change_Indication NON e' controllato\r\n"));
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Stream_Format_Change_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Stream_Format_Change_Indication\r\n"));
                Display(("BD_ADDR:     %s\r\n", Callback_BoardStr));
               // if((A3DPOpened) && (COMPARE_BD_ADDR(A2DPRemoteBD_ADDR, AUD_Event_Data->Event_Data.AUD_Stream_Format_Change_Indication_Data->BD_ADDR)))
               //    ReconfigureA3DPStream(&(AUD_Event_Data->Event_Data.AUD_Stream_Format_Change_Indication_Data->StreamFormat));
                break;
    
    
    
             case etAUD_Signalling_Channel_Open_Indication:
              	Display(("etAUD_Signalling_Channel_Open_Indication NON e' controllato\r\n"));
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Signalling_Channel_Open_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Signalling_Channel_Open_Indication\r\n"));
                Display(("BD_ADDR:  %s\r\n", Callback_BoardStr));
                break;
    
             case etAUD_Signalling_Channel_Close_Indication:
    			Display(("etAUD_Signalling_Channel_Close_Indication NON e' controllato\r\n"));
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Signalling_Channel_Close_Indication_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Signalling_Channel_Close_Indication\r\n"));
                Display(("BD_ADDR:  %s\r\n", Callback_BoardStr));
                Display(("DisconnectReason: %d\r\n", AUD_Event_Data->Event_Data.AUD_Signalling_Channel_Close_Indication_Data->DisconnectReason));
                break;
    
             case etAUD_Remote_Control_Command_Confirmation:
            	Display(("etAUD_Remote_Control_Command_Confirmation NON e' controllato\r\n"));
            	BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->BD_ADDR, Callback_BoardStr);
                Display(("etAUD_Remote_Control_Command_Confirmation\r\n"));
                Display(("BD_ADDR:            %s\r\n", Callback_BoardStr));
                Display(("TransactionID:      %d\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->TransactionID));
                Display(("ConfirmationStatus: %d\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->ConfirmationStatus));
    
                /* Check to see if this is a passthrough command.           */
                if((AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData.MessageType == amtPassThrough) && (AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->ConfirmationStatus == AUD_REMOTE_CONTROL_COMMAND_CONFIRMATION_STATUS_SUCCESS))
                {
                   Display(("Pass Through Response Code: 0x%02X\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData.MessageData.PassThroughResponseData.ResponseCode));
    
                   /* Verify that the Pass through command was successful.  */
                   if(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData.MessageData.PassThroughResponseData.ResponseCode == AVRCP_RESPONSE_ACCEPTED)
                   {
                      /* Check to see if this is a play or pause command.   */
                      if(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData.MessageData.PassThroughResponseData.OperationID == AVRCP_PASS_THROUGH_ID_PAUSE)
                      {
                         Display(("Successfully paused stream\r\n"));
    
                         /* Go ahead and flag that streaming is being       */
                         /* stopped.  Even if the stream is not stopped by  */
                         /* the remote device for some number of seconds we */
                         /* need to do so here to preserve the play pause   */
                         /* state.                                          */
                         StreamState = ssStopped;
                      }
                      else
                      {
                         if(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData.MessageData.PassThroughResponseData.OperationID == AVRCP_PASS_THROUGH_ID_PLAY)
                         {
                            Display(("Successfully started stream\r\n"));
    
                            /* Go ahead and flag that streaming is being    */
                            /* started.  Even if the stream is not started  */
                            /* by the remote device for some number of      */
                            /* seconds we need to do so here to preserve the*/
                            /* play pause state.                            */
                            StreamState = ssStarted;
                         }
                      }
                   }
                   else
                   {
                      if(StreamState == ssPending)
                         StreamState = A3DPPlaying?ssStarted:ssStopped;
                   }
                }
                else
                {
                   if(StreamState == ssPending)
                      StreamState = A3DPPlaying?ssStarted:ssStopped;
                }
                break;
             default:
                Display(("Unhandled AUD event: %d\r\n", AUD_Event_Data->Event_Data_Type));
                break;
          }
    
          //DisplayPrompt();
       }
    }

  • Roberto,

    A few things to try:

    1. Only change the stream state of the headset when it differs from the source. I don't think you need to always start the stream in the open confirmation. See below pseudo code as an example.

    static AUD_Stream_State_t SourceStreamState;
    static AUD_Stream_State_t SinkStreamState;
    
    static void BTPSAPI AUD_Event_Callback(unsigned int BluetoothStackID, AUD_Event_Data_t *AUD_Event_Data, unsigned long CallbackParameter)
    {
       case etAUD_Stream_Open_Indication:
          SourceStreamState = astStreamStopped;
          break;
    
       case etAUD_Stream_Open_Confirmation:
          SinkStreamState = astStreamStopped;
          
          if((SourceConnected) && (SourceStreamState == astStreamStarted))
          {
             if(!AUD_Change_Stream_State(BluetoothStackID, EventData->BD_ADDR, astStreamStarted))
             {
                SinkStreamState = astStreamStarted;
             }
          }
          break;
    
       case etAUD_Stream_State_Change_Indication:
          if(BD_ADDR == Source)
          {
             SourceStreamState = EventData->State;
             
             if((HeadsetConnected) && (SourceStreamState != SinkStreamState))
             {
                /* Pass the message along to the sink.                      */
                if(AUD_Change_Stream_State(BluetoothStackID, HeadsetBD_ADDR, SourceStreamState) == 0)
                   SinkStreamState = SourceStreamState;
             }
          }
          else if(BD_ADDR == Headset)
          {
             SinkStreamState = EventData->State;
             
             if((SourceConnected) && (SinkStreamState != SourceStreamState))
             {
                /* Pass the message along to the source.                    */
                if(AUD_Change_Stream_State(BluetoothStackID, SourceBD_ADDR, SinkStreamState) == 0)
                   SourceStreamState = SinkStreamState;
             }
          }
          break;
    
       case etAUD_Stream_State_Change_Confirmation:
          if(EventData->Successful == FALSE)
          {
             /* This will likely never happen, log it if it does though.    */
             Display(("etAUD_Stream_State_Change_Confirmation unsuccessful, BD_ADDR: %s.\r\n", BD_ADDRStr));
          }
          break;
    }

    2. Try switching the Bluetooth role in the etAUD_Stream_Open_Confirmation and etAUD_Stream_State_Change_Indication events. There is an example of this in the A3DPDemo_SNK app, you can use the code as follows:

    Byte_t StatusResult;
    
    if((HCI_Switch_Role(BluetoothStackID, Event_Data->BD_ADDR, HCI_ROLE_SWITCH_BECOME_MASTER, &StatusResult) != 0) || (StatusResult != 0))
       Display(("Error in HCI_Switch_Role().\r\n"));

    3. Are you using the latest SP found here: http://processors.wiki.ti.com/index.php/CC256x_Downloads, SP 1.2?

    Thanks,
    Samuel

  • Hi Samuel, 

    1. I agree with you about not always forcing the streaming state to active, however it should not be relevant at this stage of development.

    2. Tried now, it returns success but nothing changes.

    3.I'm using CC256XQFNEM (CC2564) how can I see if I'm using SP 1.2? (As IDE I'm using CC if relevant)

    4.I started working on the GAVD one, Any idea what GAVD_AVDTP_ERROR_BAD_HEADER_FORMAT means? I stumbled on it in in etGAVD_Discover_Confirmation (sent to the tiva by headset1):

    edit: I think I solved point 4 the TSEP should be tspSRC 

  • Roberto,

    1. I agree it shouldn't matter, but if the stream is started too early it may throw off the headset's buffering logic. Depends on the headset's implementation.

    2. Did you try it in both the open indication and the open confirmation? It will help if you are the master of both connections.

    3. If you are using Tiva SDK 1.2 R2 then you are using SP 1.0. There is some version information in the comments of CC256XB.h that you can use to confirm. Please upgrade to SP 1.2 from processors.wiki.ti.com/.../CC256x_Downloads. You only need the "CC2564B BT 4.0 SP" patch since you are not using A3DP nor BLE. There are instructions at the link on how to convert the BTS file to a C array like is seen in CC256XB.h.

    Thanks,
    Samuel
  • Thanks again Samuel,

    1)Ok, It will not hurt to give it a try.

    2)Yes I did the operation in both (in this moment I can't remember if I checked the success of the open indication one)

    3)Yes In Cxxx.h I can see I'm using SP1.0, I'll switch to SP1.2 and will try again the aud-api
  • Samuel, adding the patch make the system work with one headset perfectly!!!!! I'm adding the stream state handling logic right now and by monday I'll try to make the second headset work too. Do you think i should change anything in the AUD initialize configuration to let the code assume that there are 2 headset?
  • I made it work using the aud api, the sound is nice and good. I'll have to clean and comment my code in the next days, I got a couple of question:

    1. This is pretty naive but how can I save in the rom a couple of address I want to autoconnect to? 
    2. I think I read in some other topic that you were about to add the HFP open_remote_server implementation (If I remember the name correctly, it is the function that was missing and the reason I switched to A2DP), is that true?
    3. There was any particular reason why that function was not shipped in the earlier version of the stack? 

    Again thanks a lot Samuel for all your wonderfull support.

  • Roberto,

    "Do you think i should change anything in the AUD initialize configuration to let the code assume that there are 2 headset?"

    Are you connecting to 2 headsets simultaneously? If you so you can use the AUD_STREAM_INITIALIZATION_FLAGS_NUMBER_CONCURRENT_STREAMS_PRESENT flag in the InitializationFlags member of AUD_Stream_Initialization_Info_t and set NumberConcurrentStreams to something greater than 1, the exact value depends on the number of simultaneous headset connections you want to support.

    1. You just need to save the BD_ADDR and the link key from pairing to ROM. The link key is dispatched in atLinkKeyCreation event of the GAP_Event_Callback() function. When you receive the atLinkKeyRequest event during reconnection respond with the saved link key. There are examples of saving link keys in all of the A2DP & A3DP Tiva samples. Refer to the LinkKeyInfo array within the apps.

    2. The audio gateway role is what is missing, therefore the HFRE_Open_Remote_HandsFree_Port() function is not implemented. Not sure exactly what your use case is but I don't think that is what you want based on what I've heard so far. HFP is used for phone call audio and A2DP is used for high quality audio, for example music.There are currently no plans to add the HFP audio gateway role to the SDK.

    3. The role is rarely requested, that's why it wasn't included.

    Thanks,
    Samuel

  • Thanks again Samuel as I said the cxx patch really did the magic!

    I think is all for the aud-api part. I would like to move the conversation to the HFP part now.

    Other than the music we will need to stream toward 2 headsets voice calls and data too so I think implementing HFP AG will be mandatory (I don't actually know if I will be the one to do that since I was only commissioned for the music part). I already made another post about HFP AG if you plan to help: e2e.ti.com/.../1559204

    At the moment I'm only looking into the problem and studying the protocol since I have some other projects to end by the end of next two weeks. I think I'll be able to put up some effort from 15 july.

    ps. I dind't use the original post about HFP because there I was talking about using the HFP API while in the new one I will face the argument about how to write the function that is missing.

    ps2. I just noticed the post I wrote last week didn't reach the forum... The 2 headsets configuration is working fine Samuel!