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.

How to implement AVRCP profile for Control playing music on the phone?

Other Parts Discussed in Thread: CC2564, TI-BT-STACK-LINUX-ADDON

Dear StoneStreet:

 We used the STM3240G-EVAL platform sample to handle A2DP and AVRCP related function, and Porting code on the efm32GG platform.
 We want to on the efm32GG platform implement AVRCP profile for Control playing music on the phone, and get metadata information on the track itself (artist, track name, etc.)
 I found the fuction named SendPassThroughCommand can send the request to target(handset).
 but how to get the metadata information on the track?

  if possible , can you get the sample code to show how to do ?

Thanks

  • We found STM3240G-EVAL platform AVRCP sample can not playing music on the phone when Porting code on the efm32GG platform.
    and although we used the fuction named SendPassThroughCommand can send the request to target(handset).
  • hi ,
    Add more for description for this question support need.
    In current platform, smart phone will display with two device (one is Headset, another is BT device) when CC2564 BT is enable, then the Headset will be the default one, but if the Default one is BT device, the phone will play music with audio, and user can control Android for the music player via CC2564 BT, could we have this done with software update.

    Regards
    Andy
  • Andy,

    The setup description is not very clear to me. Perhaps a block diagram showing the setup will help clarifying it.

    Miguel
  • Miguel,

    It is smart watch case with CC2564 din, customer spec require is that user could control phone by smart watch via Bluetooth, such as selecting song, Volume +/-… it is only control, and all the music audio will keep output via phone speaker.

     

    Customer developed it based on TI CC2564B ref design. When it works, smart phone could find BT device(K3 Watch), and there were two option (Iphone, K3 Watch) when start playing music, as K3 Watch was selected by default, the phone will play music but the audio won’t output by speaker, then customer need if Iphone could be selected by default then the audio will output by speaker, can we make it done by CC2564 HCI modification or any other Profile can make it work?

     

    Another question is customer want smart watch to display the music information(such as music name, music content) in LCD, how to have CC2564 receive these information from smart phone and show in the LCD? May there were some HCI could do it?

     

     Pls kindly let me know if any unclear, thanks

     

    Regards,

    Andy

  • Andy,

    I think I understand what you are asking. You want to be able to control the iPhone with AVRCP, but you do not want the iPhone to send music to the watch, is this correct? If so, you can initialize the AUD module without the A2DP profile. For example, in A3DPDemo_SNK this can be done by changing the following line from:

             InitializationInfo.SNKInitializationInfo           = &InitializationInfoSNK;

    to:

             InitializationInfo.SNKInitializationInfo           = NULL;

    After this, the iPhone will see that your watch does not support A2DP and will not try to send audio to it. Please let me know if this isn't what you are looking for.

    As for getting the artist and track name information, this can be done with the AVRCP message type amtGetElementAttributes. The following command is taken from a soon-to-be-released TI-BT-STACK-LINUX-ADDON SDK from the LinuxAUD.c demo. You should be able to add it to the A3DPDemo_SNK demo with little to no modifications:

       /* The following function is responsible for Sending a Remote Control*/
       /* (AVRCP) Get Element Attributes Command to retrieve the currently  */
       /* playing track information from a connected AVRCP Target.  This    */
       /* function returns zero if successful and a negative value if an    */
       /* error occurred.                                                   */
       /* * NOTE * Both the local and remote device must support an AVRCP   */
       /*          Version greater than or equal to 1.3 to use this command.*/
    static int SendRemoteControlGetTrackInformationCommand(ParameterList_t *TempParam)
    {
       int                               ret_val;
       int                               Result;
       unsigned int                      Index;
       Boolean_t                         DisplayUsage;
       BD_ADDR_t                         RemoteDevice;
       AUD_Remote_Control_Command_Data_t CommandData;
       unsigned int                      AttributeIDsIndex;
       unsigned int                      AttributeIDsCount;
       DWord_t                           AttributeIDs[AVRCP_MEDIA_ATTRIBUTE_ID_PLAYING_TIME_MS];
    
       /* First, check to make sure that we have already been initialized.  */
       if(BluetoothStackID)
       {
          DisplayUsage      = FALSE;
    
          AttributeIDsIndex = 1;
    
          /* Make sure that all of the parameters required for this      */
          /* function appear to be at least semi-valid.                  */
          if((TempParam) && (TempParam->NumberofParameters > AttributeIDsIndex) && (TempParam->Params[0].strParam))
          {
             /* Note the input parameters.                               */
             StrToBD_ADDR(TempParam->Params[0].strParam, &RemoteDevice);
    
             Result            = 0;
             AttributeIDsCount = 0;
    
             if(TempParam->Params[AttributeIDsIndex].intParam == 0)
             {
                CommandData.MessageData.GetElementAttributesCommandData.AttributeIDList = NULL;
             }
             else
             {
                for(Index = AttributeIDsIndex; Index < ((unsigned int)TempParam->NumberofParameters); Index++)
                {
                   if((TempParam->Params[Index].intParam >= AVRCP_MEDIA_ATTRIBUTE_ID_TITLE_OF_MEDIA) && (TempParam->Params[Index].intParam <= AVRCP_MEDIA_ATTRIBUTE_ID_PLAYING_TIME_MS))
                   {
                      AttributeIDs[AttributeIDsCount++] = (DWord_t)TempParam->Params[Index].intParam;
                   }
                   else
                   {
                      Result = INVALID_PARAMETERS_ERROR;
    
                      break;
                   }
                }
    
                if(!Result)
                {
                   CommandData.MessageData.GetElementAttributesCommandData.AttributeIDList = AttributeIDs;
                }
             }
    
             if(!Result)
             {
                /* Build the response.                                      */
                CommandData.MessageType                                                  = amtGetElementAttributes;
                CommandData.MessageData.GetElementAttributesCommandData.Identifier       = AVRCP_ELEMENT_IDENTIFIER_PLAYING;
                CommandData.MessageData.GetElementAttributesCommandData.NumberAttributes = AttributeIDsCount;
    
                /* Try to Send the Message.                           */
                if((Result = AUD_Send_Remote_Control_Command(BluetoothStackID, RemoteDevice, &CommandData, DEFAULT_AVRCP_COMMAND_TIMEOUT)) >= 0)
                {
                   printf("Remote Control Command Sent: Transaction ID = %d\r\n", Result);
       
                   /* Flag success to the caller.                     */
                   ret_val = 0;
                }
                else
                {
                   /* Error in the API call. Inform the user and flag */
                   /* an error.                                       */
                   printf("AUD_Send_Remote_Control_Command() Failure: %d.\r\n", Result);
    
                   ret_val = FUNCTION_ERROR;
                }
             }
             else
             {
                DisplayUsage = TRUE;
    
                ret_val      = FUNCTION_ERROR;
             }
          }
          else
          {              
             DisplayUsage = TRUE;
    
             ret_val      = INVALID_PARAMETERS_ERROR;
          }
    
          if(DisplayUsage)
          {
             /* One or more of the necessary parameters is/are invalid.  */
             printf("Usage: SendRemoteControlGetTrackInformationCommand [BD_ADDR] [[GetAll = 0] || [[Attribute ID] [Attribute ID] ...]]\r\n");
             printf("Get All Attributes Example: SendRemoteControlGetTrackInformationCommand 010203040506 0\r\n");
             printf("Attribute IDs:\r\n");
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_ILLEGAL:               0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_ILLEGAL);              
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_TITLE_OF_MEDIA:        0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_TITLE_OF_MEDIA);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ARTIST:        0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ARTIST);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ALBUM:         0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ALBUM);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_NUMBER_OF_MEDIA:       0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_NUMBER_OF_MEDIA);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_TOTAL_NUMBER_OF_MEDIA: 0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_TOTAL_NUMBER_OF_MEDIA);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_GENRE:                 0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_GENRE);
             printf("   AVRCP_MEDIA_ATTRIBUTE_ID_PLAYING_TIME_MS:       0x%08X\r\n", AVRCP_MEDIA_ATTRIBUTE_ID_PLAYING_TIME_MS);      
          }
       }
       else
       {
          /* A valid Stack ID does not exist, inform to user.               */
          printf("Stack not Initialized.\r\n");
    
          ret_val = UNABLE_TO_INITIALIZE_STACK;
       }
    
       return(ret_val);
    }

    The response event can be handled with code similar to this in AUD_Event_Callback():

             case etAUD_Remote_Control_Command_Confirmation:
                printf("\nAUD: Remote Control Command Confirmation.\r\n");
                BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->BD_ADDR, BoardStr);
                printf("    Address      : %s\r\n", BoardStr);
                printf("    TransactionID: %u\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->TransactionID);
                printf("    Status       : %d\r\n", AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->ConfirmationStatus);
                if(!(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->ConfirmationStatus))
                   ProcessRemoteControlCommandConfirmation(&(AUD_Event_Data->Event_Data.AUD_Remote_Control_Command_Confirmation_Data->RemoteControlResponseData));         
                break;

    Where the ProcessRemoteControlCommandConfirmation() looks like this:

       /* The following function handles processing a Remote Control Command*/
       /* Confirmation.                                                     */
    static void ProcessRemoteControlCommandConfirmation(AUD_Remote_Control_Response_Data_t *ResponseData)
    {
       char                                 *Message;
       unsigned int                          Index;
       char                                  TempArr[150];
       Boolean_t                             Success;
       AVRCP_Element_Attribute_List_Entry_t *AttributeList;
    
       /* Display a notification for any message type.                      */
       switch(ResponseData->MessageType)
       {
          case amtUnknown:
             Message = "Unknown";
             break;
          case amtUnitInfo:
             Message = "UnitInfo";
             break;
          case amtSubunitInfo:
             Message = "SubunitInfo";
             break;
          case amtPassThrough:
             Message = "PassThrough";
             break;
          case amtVendorDependent_Generic:
             Message = "VendorDependent_Generic";
             break;
          case amtBrowsingChannel_Generic:
             Message = "BrowsingChannel_Generic";
             break;
          case amtFragmentedMessage:
             Message = "FragmentedMessage";
             break;
          case amtGroupNavigation:
             Message = "GroupNavigation";
             break;
          case amtGetCapabilities:
             Message = "GetCapabilities";
             break;
          case amtListPlayerApplicationSettingAttributes:
             Message = "ListPlayerApplicationSettingAttributes";
             break;
          case amtListPlayerApplicationSettingValues:
             Message = "ListPlayerApplicationSettingValues";
             break;
          case amtGetCurrentPlayerApplicationSettingValue:
             Message = "GetCurrentPlayerApplicationSettingValue";
             break;
          case amtSetPlayerApplicationSettingValue:
             Message = "SetPlayerApplicationSettingValue";
             break;
          case amtGetPlayerApplicationSettingAttributeText:
             Message = "GetPlayerApplicationSettingAttributeText";
             break;
          case amtGetPlayerApplicationSettingValueText:
             Message = "GetPlayerApplicationSettingValueText";
             break;
          case amtInformDisplayableCharacterSet:
             Message = "InformDisplayableCharacterSet";
             break;
          case amtInformBatteryStatusOfCT:
             Message = "InformBatteryStatusOfCT";
             break;
          case amtGetElementAttributes:
             Message = "GetElementAttributes";
             break;
          case amtGetPlayStatus:
             Message = "GetPlayStatus";
             break;
          case amtRegisterNotification:
             Message = "RegisterNotification";
             break;
          case amtRequestContinuingResponse:
             Message = "RequestContinuingResponse";
             break;
          case amtAbortContinuingResponse:
             Message = "AbortContinuingResponse";
             break;
          case amtSetAbsoluteVolume:
             Message = "SetAbsoluteVolume";
             break;
          case amtCommandRejectResponse:
             Message = "CommandRejectResponse";
             break;
          case amtSetAddressedPlayer:
             Message = "SetAddressedPlayer";
             break;
          case amtPlayItem:
             Message = "PlayItem";
             break;
          case amtAddToNowPlaying:
             Message = "AddToNowPlaying";
             break;
          case amtSetBrowsedPlayer:
             Message = "SetBrowsedPlayer";
             break;
          case amtChangePath:
             Message = "ChangePath";
             break;
          case amtGetItemAttributes:
             Message = "GetItemAttributes";
             break;
          case amtSearch:
             Message = "Search";
             break;
          case amtGetFolderItems:
             Message = "GetFolderItems";
             break;
          case amtGeneralReject:
             Message = "GeneralReject";
             break;
          default:
             Message = "Unknown";
             break;
       }
    
       printf("    Message Type : %s\r\n", Message);
    
       /* Handle the message types that this application supports.          */
       switch(ResponseData->MessageType)
       {
          case amtPassThrough:
             DisplayRemoteControlResponseCode("       Response Code: ", ResponseData->MessageData.PassThroughResponseData.ResponseCode, "\r\n");
             printf("       Subunit Type : %u\r\n", ResponseData->MessageData.PassThroughResponseData.SubunitType);
             printf("       Subunit ID   : %u\r\n", ResponseData->MessageData.PassThroughResponseData.SubunitID);
             printf("       Operation ID : %u\r\n", ResponseData->MessageData.PassThroughResponseData.OperationID);
             printf("       State Flag   : %s\r\n", (ResponseData->MessageData.PassThroughResponseData.StateFlag == FALSE)?"FALSE":"TRUE");
             printf("       Data Length  : %u\r\n", ResponseData->MessageData.PassThroughResponseData.OperationDataLength);
             break;
          case amtGetElementAttributes:
             AttributeList = ResponseData->MessageData.GetElementAttributesResponseData.AttributeList;
             
             if(ResponseData->MessageData.GetElementAttributesResponseData.ResponseCode == AVRCP_RESPONSE_STABLE)
             {
                printf("    Attributes:\r\n");
    
                for(Index = 0; Index < ResponseData->MessageData.GetElementAttributesResponseData.NumberAttributes; Index ++)
                {
                   Success = TRUE;
    
                   switch(AttributeList[Index].AttributeID)
                   {
                      case AVRCP_MEDIA_ATTRIBUTE_ID_ILLEGAL:               printf("       Illegal Attribute\r\n"); Success = FALSE;    break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_TITLE_OF_MEDIA:        printf("       Title:             ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ARTIST:        printf("       Artist:            ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_NAME_OF_ALBUM:         printf("       Album:             ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_NUMBER_OF_MEDIA:       printf("       Track Number:      ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_TOTAL_NUMBER_OF_MEDIA: printf("       Total Num Tracks:  ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_GENRE:                 printf("       Genre:             ");                       break;
                      case AVRCP_MEDIA_ATTRIBUTE_ID_PLAYING_TIME_MS:       printf("       Track Length (ms): ");                       break;
                      default:                                             printf("       Unknown Attribute\r\n"); Success = FALSE;    break;
                   }
    
                   if(Success)
                   {
                      if(AttributeList[Index].AttributeValueLength < sizeof(TempArr))
                      {
                         /* Copy the string and then null terminate it.     */
                         BTPS_MemCopy(TempArr, AttributeList[Index].AttributeValueData, AttributeList[Index].AttributeValueLength);
                         TempArr[AttributeList[Index].AttributeValueLength] = 0;
                      }
                      else
                      {
                         /* The string won't fit in the array, copy and     */
                         /* truncate the string.                            */
                         BTPS_MemCopy(TempArr, AttributeList[Index].AttributeValueData, (sizeof(TempArr) - 1));
                         TempArr[sizeof(TempArr) - 1] = 0;
                      }
    
                      printf("%s\r\n", TempArr);
                   }
                }
             }
             else
             {
                DisplayRemoteControlResponseCode("    Response Code: ", ResponseData->MessageData.GetElementAttributesResponseData.ResponseCode, " [Error: Response != AVRCP_RESPONSE_STABLE]\r\n");
             }
             break;
          case amtGetPlayStatus:
             DisplayRemoteControlResponseCode("    Response Code: ", ResponseData->MessageData.GetPlayStatusResponseData.ResponseCode, "\r\n");
             printf("    Status       : ");
             DisplayRemoteControlPlaybackStatus(ResponseData->MessageData.GetPlayStatusResponseData.PlayStatus);
             printf("\r\n");
    
             printf("    Song Length  : ");
             if(ResponseData->MessageData.GetPlayStatusResponseData.SongLength != 0xFFFFFFFF)
                printf("%lu:%02lu\r\n", ((ResponseData->MessageData.GetPlayStatusResponseData.SongLength / 1000) / 60), ((ResponseData->MessageData.GetPlayStatusResponseData.SongLength / 1000) % 60));
             else
                printf("0x%lX (Not Supported)\r\n", ResponseData->MessageData.GetPlayStatusResponseData.SongLength);
    
             printf("    Song Position: ");
             if(ResponseData->MessageData.GetPlayStatusResponseData.SongPosition != 0xFFFFFFFF)
                printf("%lu:%02lu\r\n", ((ResponseData->MessageData.GetPlayStatusResponseData.SongPosition / 1000) / 60), ((ResponseData->MessageData.GetPlayStatusResponseData.SongPosition / 1000) % 60));
             else
                printf("0x%lX (Not Supported)\r\n", ResponseData->MessageData.GetPlayStatusResponseData.SongPosition);
    
             break;
          default:
             break;
       }
    }

    Note that you will need to change your AVRCP version from 1.0 to 1.3. This can be done in A3DPDemo_SNK in the Initialize_Sink() function by changing the following line from:

             InitializationInfoAVR.SupportedVersion             = apvVersion1_0;

    to:

             InitializationInfoAVR.SupportedVersion             = apvVersion1_3;

    Hope this helps. Please let me know if you have any other questions.

    Thanks,
    Samuel

  • Dear Miguel,

    If the phone is ios system, there is no problem.
    But If the phone is android system, the response event can not be received from AUD_Event_Callback();
    And the following log information will not appear:


    case etAUD_Remote_Control_Open_Confirmation:
    BD_ADDRToStr(AUD_Event_Data->Event_Data.AUD_Remote_Control_Open_Confirmation_Data->BD_ADDR, BoardStr);
    Display(("\r\nAUD Open Remote Control Confirmation: %s, %d.\r\n", BoardStr, AUD_Event_Data->Event_Data.AUD_Remote_Control_Open_Confirmation_Data->OpenStatus));
    if(!AUD_Event_Data->Event_Data.AUD_Remote_Control_Open_Confirmation_Data->OpenStatus)
    RemoteControlConnection = TRUE;
    ConnectedBD_ADDR = AUD_Event_Data->Event_Data.AUD_Remote_Control_Open_Confirmation_Data->BD_ADDR;
    break;

    Pls kindly let me know if any unclear, thanks

    Regards,

  • Dear Miguel,

    Customer pointed out where the program runs when the issue occur for Android. And I add more test input for these actions update, better for your understanding.

    1. Customer had some modification based on A3DPDemo_SNK.c, copy your suggestion, and

    use InitializationInfo.SNKInitializationInfo           = NULL;

    instead of InitializationInfo.SNKInitializationInfo        = &InitializationInfoSNK; 

     

    It is found worse case than before, the music player could not be controlled by smart watch, even Prep/Next one selection did not work, pls find related Log with attached Log1.txt.

     

    2. Customer had some modification based on A3DPDemo_SNK.c, copy your suggestion, but

    keep using InitializationInfo.SNKInitializationInfo        = &InitializationInfoSNK; 

    It is found there is no improved so far, music player could be controlled by smart watch for Prep/Next one selection, but need select the device by handle, pls find related Log with attached Log2.txt.

     

     

    3.   But meanwhile customer do some improvement with some modification based on AUDDemo.c, and

    Use InitializationInfo.SNKInitializationInfo           = NULL;

    instead of InitializationInfo.SNKInitializationInfo        = &InitializationInfoSNK; 

    It is found there is some improved so far, for IOS phone, music player could be controlled by smart watch for Prep/Next one selection, and no need select the device by handle.

    But for Android, the music could not be controlled by smart watch, any suggestion

     

    4. With your suggestion, we have finished making the smart watch display the information of music.

     

    Appreciate your support, let’s know if any unclear, thanks.

    Regards,

    Andy

    log.rar

  • Hi Andy,

    This seems to be a problem on the Android not supporting an AVRCP only connection.

    Regards,
    Gigi Joseph.
  • Hi Gigi,

    I found the "pebble and fitbit" watch can support remote control music play and pause when the phone is android system.
    They use the same chip(CC2564B), so the CC2564B can support the AVRCP profile and implement remote control music play and pause.
    We need to use cc2564B implement remote control music play and pause when the phone is android or ios system.
    We used AUDdemo sample of the STM3240G-EVAL platform, and porting AUDDemo.c code to the efm32GG platform,

    And if we try changing the following line from:


              InitializationInfo.SNKInitializationInfo = &InitializationInfoSNK;
    to:

             InitializationInfo.SNKInitializationInfo = NULL;


    the android phone can not be remote control music play and pause, but the ios phone is ok.
    can you tell me the solution of the problem? Thanks

    Regards

    Justin Huang.

  • Hi Justin,

    The android behaviour is to treat the AVRCP profile as part of the A2DP profile and connect them together. You can see the attached snoop log (taken with CC256xB and and Android phone) where the CC2564B device initiates an AVRCP (AVCTP_Control) connection which gets accepted by the Android phone. THe Android phone then does an SDP for A2DPSink profile.  When it finds no results, it terminates the AVRCP connection.

    Can you share the android snoop logs in the working case? It's very weird that it works without any 3rd party application enabling this sort of connection on the Android side.

    Regards,
    Gigi Joseph.


    test.cfa

  • Hi Gigi,

    We used AUDdemo sample of the STM3240G-EVAL platform, and porting AUDDemo.c file to the efm32GG platform.
    And send "SendPassThroughCommand" Command to android phone When catch related Log information by BPA600.
    We get related Log information:

    1) "InitializationInfo.SNKInitializationInfo = NULL", pls find related Log with attached SNKInitializationInfo_is_null.rar;
    2) "InitializationInfo.SNKInitializationInfo = &InitializationInfoSNK", pls find related Log with attached SNKInitializationInfo_is_not_null.zip;

    We hope to use cc2564B device implement remote control phone music play and pause when the phone is android or ios system.
    can you tell me the solution of the problem? Thanks

    Regards

    Justin Huang.

    SNKInitializationInfo_is_not_null.zip

    SNKInitializationInfo_is_null.rar

  • Hi Justin,

    I can only see the "SNKInitializationInfo_is_not_null.cfa" in the downloads. It behaves as expected.

    As Samuel mentioned, setting "InitializationInfo.SNKInitializationInfo = NULL" disables the A2DP profile on your local device which is what you need.

    The reason why Android has issues with "InitializationInfo.SNKInitializationInfo = NULL" is because Android is expecting both the A2DP/AVRCP profiles together. So once your device indicates that it supports only AVRCP profile, Android is disconnecting the AVRCP channel.

    You can attach the "SNKInitializationInfo_is_null.cfa" log and I can confirm it.

    The way to move forward with this issue are:

    (1) Since you mentioned: "I found the 'pebble and fitbit' watch can support remote control music play and pause when the phone is android system." , please share a snoop/air sniffer log for this case, so I can take a look.

    (2) Check on some Android forums (external) and see if there is any way to bypass this Android limitation.

    Regards,
    Gigi Joseph.
  • Hi Gigi,

    We get related Log information:

    1) "InitializationInfo.SNKInitializationInfo = NULL", pls find attached SNKInitializationInfo_is_null.rar;
    2) Get fitbit watch related Log information when remote control phone music play, pls find attached fitbit_android.rar;
    3) Get pebble watch related Log information when remote control phone music play, pls find attached pebble_android.rar;

    Thanks

    Regards.

    Justin Huang.

    fitbit_android.rar

    pebble_android.rar

    SNKInitializationInfo  is  null.rar

  • Hi Justin,

    Thanks for the logs, please see below what I could find.

    SNKInitializationInfo_is_null.rar
    As expected, the Android phone does not initiate (only) the AVRCP connection as soon as it finds that the remote side does not support A2DP profile.

    fitbit_android.rar
    There are no BR/EDR connection/attempt between the two devices. All I see are some advertisement packets.

    pebble_android.rar
    I see an SDP connection request from the phone (master), but later there are a lot of CRC errors so it's unclear what the data exchange was.

    Can you please share a snoop log from the android phone (for pebble/fitbit case)? Do they also have an app running on Android?

    Regards,
    Gigi Joseph.
  • Hi Gigi,

    We get related Log information again:

    1) Get fitbit watch related Log information when remote control phone music play, pls find attached fitbit_android_02.rar;
    2) Get pebble watch related Log information when remote control phone music play, pls find attached pebble_android_02.rar;

    We hope to use cc2564B device implement remote control phone music play and pause when the phone is android or ios system.

    We are try  change   "InitializationInfo.SNKInitializationInfo = &InitializationInfoSNK; "   to  "InitializationInfo.SNKInitializationInfo = NULL"  , 

    and  get related Log information,

    However  we can not  still control phone music play and pause when the phone is android or ios system.

    can you tell me the solution of the problem? Thanks

    Regards

    Justin Huang.

    pebble_android_02.rar

    fitbit_android_02.rar

  • Hi Justin,

    In both these logs, there is no indication of either an A2DP or an AVRCP connection.
    As requested, please share a snoop log from the Android phone side.

    Please also tell me if there is a custom application running on the Android side. My best guess is that this Android application is receiving some command from the phone (either via SPP or BLE) and then instructing the media player to play/pause (this is not AVRCP, but some SPP based profile). But I cannot tell without seeing the proper logs.

    Regards,
    Gigi Joseph.
  • Hi now I'm at this point:
    Android is expecting both the A2DP/AVRCP profiles together. So once your device indicates that it supports only AVRCP profile, Android is disconnecting the AVRCP channel.

    There is nothing new about this problem?
  • Hi,

    This is an Android issue - I'm not sure if they've changed this behaviour. Maybe you can check on some Android forums (external).

    Regards,
    Gigi Joseph.
  • Hi Joseph testing again this behaviour, using AUD_Open_Remote_Control function provided by TI i think i found something useful.

    This is a capture using the AUD_Open_Remote_Control function again and again, the pattern is always the same, the phone connects and just a second disconnects.

    Can you check the SDP response from TI? Of corse the same example using one Apple device is working fine.

  • Hi,

    It's already analysed. Android phones are not connecting to devices that has only the AVRCP profile (and not A2DP + AVRCP profile). iPhone doesn't have this behaviour.

    Regards.
    Gigi Joseph.