From: Lucas De Marchi <hidden> Date: 2011-08-05 18:15:13
ChangeSetting() is used by an application to inform bluetoothd that a
certain media player setting was changed.
---
audio/control.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 152 insertions(+), 0 deletions(-)
@@ -423,6 +455,81 @@ static void handle_panel_passthrough(struct control *control,operands[0]&0x7F,status);}+staticintattrval_to_val(uint8_tattr,constchar*value){+intret;++switch(attr){+casePLAYER_SETTING_EQUALIZER:+if(!strcmp(value,"off"))+ret=EQUALIZER_MODE_OFF;+elseif(!strcmp(value,"on"))+ret=EQUALIZER_MODE_ON;+else+ret=-EINVAL;++returnret;+casePLAYER_SETTING_REPEAT:+if(!strcmp(value,"off"))+ret=REPEAT_MODE_OFF;+elseif(!strcmp(value,"singletrack"))+ret=REPEAT_MODE_SINGLE;+elseif(!strcmp(value,"alltracks"))+ret=REPEAT_MODE_ALL;+elseif(!strcmp(value,"group"))+ret=REPEAT_MODE_GROUP;+else+ret=-EINVAL;++returnret;+casePLAYER_SETTING_SHUFFLE:+if(!strcmp(value,"off"))+ret=SHUFFLE_MODE_OFF;+elseif(!strcmp(value,"alltracks"))+ret=SHUFFLE_MODE_ALL;+elseif(!strcmp(value,"group"))+ret=SHUFFLE_MODE_GROUP;+else+ret=-EINVAL;++returnret;+casePLAYER_SETTING_SCAN:+if(!strcmp(value,"off"))+ret=SCAN_MODE_OFF;+elseif(!strcmp(value,"alltracks"))+ret=SCAN_MODE_ALL;+elseif(!strcmp(value,"group"))+ret=SCAN_MODE_GROUP;+else+ret=-EINVAL;++returnret;+}++return-EINVAL;+}++staticintattr_to_val(constchar*str)+{+if(!strcmp(str,"Equalizer"))+returnPLAYER_SETTING_EQUALIZER;+elseif(!strcmp(str,"Repeat"))+returnPLAYER_SETTING_REPEAT;+elseif(!strcmp(str,"Shuffle"))+returnPLAYER_SETTING_SHUFFLE;+elseif(!strcmp(str,"Scan"))+returnPLAYER_SETTING_SCAN;++return-EINVAL;+}++staticvoidmp_set_attribute(structmedia_player*mp,+uint8_tattr,uint8_tval)+{+DBG("Change attribute: %u %u",attr,val);++mp->settings[attr]=val;+}+/* handle vendordep pdu inside an avctp packet */staticinthandle_vendordep_pdu(structcontrol*control,structavrcp_header*avrcp,
@@ -1129,7 +1236,52 @@ static GDBusSignalTable control_signals[] = {{NULL,NULL}};+staticDBusMessage*mp_change_setting(DBusConnection*conn,+DBusMessage*msg,void*data)+{+structaudio_device*device=data;+structcontrol*control=device->control;+DBusMessageIteriter;+DBusMessageItervar;+constchar*attrstr,*valstr;+intattr,val;++if(!dbus_message_iter_init(msg,&iter))+returnbtd_error_invalid_args(msg);++if(dbus_message_iter_get_arg_type(&iter)!=DBUS_TYPE_STRING)+returnbtd_error_invalid_args(msg);++dbus_message_iter_get_basic(&iter,&attrstr);++attr=attr_to_val(attrstr);+if(attr<0)+returnbtd_error_not_supported(msg);++dbus_message_iter_next(&iter);++if(dbus_message_iter_get_arg_type(&iter)!=DBUS_TYPE_VARIANT)+returnbtd_error_invalid_args(msg);++dbus_message_iter_recurse(&iter,&var);++/* Only string arguments are supported for now */+if(dbus_message_iter_get_arg_type(&var)!=DBUS_TYPE_STRING)+returnbtd_error_invalid_args(msg);++dbus_message_iter_get_basic(&var,&valstr);++val=attrval_to_val(attr,valstr);+if(val<0)+returnbtd_error_not_supported(msg);++mp_set_attribute(control->mp,attr,val);++returndbus_message_new_method_return(msg);+}+staticGDBusMethodTablemp_methods[]={+{"ChangeSetting","sv","",mp_change_setting},{}};
From: Lucas De Marchi <hidden> Date: 2011-08-05 18:15:14
ChangePlayback() is used by applications to inform bluetoothd of the
current status of playback.
---
audio/control.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 77 insertions(+), 0 deletions(-)
From: Lucas De Marchi <hidden> Date: 2011-08-05 18:15:15
ChangeTrack() is used by applications to inform bluetoothd that current
track changed, passing also the metadata.
---
audio/control.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 163 insertions(+), 0 deletions(-)
@@ -102,6 +102,21 @@#define FORWARD_OP 0x4b#define BACKWARD_OP 0x4c+/* Company IDs for vendor dependent commands */+#define IEEEID_BTSIG 0x001958++/* Error codes for metadata transfer */+#define E_INVALID_COMMAND 0x00+#define E_INVALID_PARAM 0x01+#define E_PARAM_NOT_FOUND 0x02+#define E_INTERNAL 0x03++/* PDU types for metadata transfer */+#define AVRCP_GET_CAPABILITIES 0x10++/* Capabilities for AVRCP_GET_CAPABILITIES pdu */+#define CAP_COMPANY_ID 0x02+#define QUIRK_NO_RELEASE 1 << 0enumplayer_setting{
@@ -277,6 +292,11 @@ static struct {{NULL}};+/* Company IDs supported by this device */+staticuint32_tcompany_ids[]={+IEEEID_BTSIG,+};+staticGSList*avctp_callbacks=NULL;staticvoidauth_cb(DBusError*derr,void*user_data);
@@ -623,13 +643,88 @@ static void mp_set_media_attributes(struct control *control,mi->ntracks,mi->track,mi->track_len);}+staticintavrcp_handle_get_capabilities(structcontrol*control,+structavrcp_spec_avc_pdu*pdu)+{+uint16_tlen=ntohs(pdu->params_len);+unsignedinti;++if(len!=1)+gotoerr;++DBG("id=%u",pdu->params[0]);++switch(pdu->params[0]){+caseCAP_COMPANY_ID:+for(i=0;i<G_N_ELEMENTS(company_ids);i++){+pdu->params[2+i*3]=company_ids[i]>>16;+pdu->params[3+i*3]=(company_ids[i]>>8)&0xFF;+pdu->params[4+i*3]=company_ids[i]&0xFF;+}++pdu->params_len=htons(2+(3*G_N_ELEMENTS(company_ids)));+pdu->params[1]=G_N_ELEMENTS(company_ids);++return2+(3*G_N_ELEMENTS(company_ids));+}++err:+pdu->params[0]=E_INVALID_PARAM;+return-EINVAL;+}+/* handle vendordep pdu inside an avctp packet */staticinthandle_vendordep_pdu(structcontrol*control,structavrcp_header*avrcp,intoperand_count){-avrcp->code=CTYPE_NOT_IMPLEMENTED;-returnAVRCP_HEADER_LENGTH;+structavrcp_spec_avc_pdu*pdu=(void*)avrcp+AVRCP_HEADER_LENGTH;+uint32_tcompany_id=(pdu->company_id[0]<<16)|+(pdu->company_id[1]<<8)|+(pdu->company_id[2]);+intlen;++if(company_id!=IEEEID_BTSIG||+pdu->packet_type!=AVCTP_PACKET_SINGLE){+avrcp->code=CTYPE_NOT_IMPLEMENTED;+returnAVRCP_HEADER_LENGTH;+}++pdu->packet_type=0;+pdu->rsvd=0;++if(operand_count+3<AVRCP_SPECAVCPDU_HEADER_LENGTH){+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++switch(pdu->pdu_id){+caseAVRCP_GET_CAPABILITIES:+if(avrcp->code!=CTYPE_STATUS){+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++len=avrcp_handle_get_capabilities(control,pdu);+if(len<0)+gotoerr_metadata;++avrcp->code=CTYPE_STABLE;++break;+default:+/* Invalid pdu_id */+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++returnAVRCP_HEADER_LENGTH+AVRCP_SPECAVCPDU_HEADER_LENGTH+len;++err_metadata:+avrcp->code=CTYPE_REJECTED;+pdu->params_len=htons(1);++returnAVRCP_HEADER_LENGTH+AVRCP_SPECAVCPDU_HEADER_LENGTH+1;}staticvoidavctp_disconnected(structaudio_device*dev)
@@ -759,6 +760,69 @@ err:return-EINVAL;}+staticintavrcp_handle_get_current_player_value(structcontrol*control,+structavrcp_spec_avc_pdu*pdu)+{+uint16_tlen=ntohs(pdu->params_len);+structmedia_player*mp=control->mp;++if(!mp)+gotodone;++if(len>1&&pdu->params[0]==len-1){+uint8_tsettings[pdu->params[0]];+unsignedinti;++/* save a copy of requested settings */+memcpy(settings,&pdu->params[1],len);+len=0;++/*+*Fromsec.5.7ofAVRCP1.3spec,weshouldigore+*non-existentIDsandsendaresponsewiththeexistent+*ones.OnlyifallIDsarenon-existentweshouldsendan+*error.+*/+for(i=0;i<pdu->params[0];i++){+uint8_tval;++if(settings[i]<PLAYER_SETTING_EQUALIZER){+DBG("Ignoring %u",settings[i]);+continue;+}++if(settings[i]>PLAYER_SETTING_SCAN){+DBG("Ignoring %u",settings[i]);+continue;+}++val=mp_get_attribute(mp,settings[i]);+if(!val){+DBG("Ignoring %u: not supported by player",+settings[i]);+continue;+}++pdu->params[len*2+1]=settings[i];+pdu->params[len*2+2]=val;+len++;+}++if(len){+pdu->params[0]=len;+pdu->params_len=htons(2*len+1);++return2*len+1;+}+}++done:+error("No valid attributes in request");+pdu->params[0]=E_INVALID_PARAM;++return-EINVAL;+}+/* handle vendordep pdu inside an avctp packet */staticinthandle_vendordep_pdu(structcontrol*control,structavrcp_header*avrcp,
@@ -824,6 +888,19 @@ static int handle_vendordep_pdu(struct control *control,avrcp->code=CTYPE_STABLE;break;+caseAVRCP_GET_CURRENT_PLAYER_VALUE:+if(avrcp->code!=CTYPE_STATUS){+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++len=avrcp_handle_get_current_player_value(control,pdu);+if(len<0)+gotoerr_metadata;++avrcp->code=CTYPE_STABLE;++break;default:/* Invalid pdu_id */pdu->params[0]=E_INVALID_COMMAND;
@@ -518,6 +519,49 @@ static unsigned int attr_get_max_val(uint8_t attr)return0;}+staticconstchar*attrval_to_str(uint8_tattr,uint8_tvalue)+{+switch(attr){+casePLAYER_SETTING_EQUALIZER:+switch(value){+case(EQUALIZER_MODE_ON):+return"on";+case(EQUALIZER_MODE_OFF):+return"off";+}++break;+casePLAYER_SETTING_REPEAT:+switch(value){+case(REPEAT_MODE_OFF):+return"off";+case(REPEAT_MODE_SINGLE):+return"singletrack";+case(REPEAT_MODE_ALL):+return"alltracks";+case(REPEAT_MODE_GROUP):+return"group";+}++break;+/* Shuffle and scan have the same values */+casePLAYER_SETTING_SHUFFLE:+casePLAYER_SETTING_SCAN:+switch(value){+caseSCAN_MODE_OFF:+return"off";+caseSCAN_MODE_ALL:+return"alltracks";+caseSCAN_MODE_GROUP:+return"group";+}++break;+}++returnNULL;+}+staticintattrval_to_val(uint8_tattr,constchar*value){intret;
@@ -669,6 +729,44 @@ static void mp_set_media_attributes(struct control *control,mi->ntracks,mi->track,mi->track_len);}+staticvoidappend_variant(DBusMessageIter*iter,inttype,void*val)+{+DBusMessageItervalue;+charsig[2]={type,'\0'};++dbus_message_iter_open_container(iter,DBUS_TYPE_VARIANT,sig,&value);++dbus_message_iter_append_basic(&value,type,val);++dbus_message_iter_close_container(iter,&value);+}++staticdbus_bool_temit_setting_changed(DBusConnection*conn,+constchar*path,+constchar*interface,+constchar*name,+inttype,void*value)+{+DBusMessage*signal;+DBusMessageIteriter;++signal=dbus_message_new_signal(path,interface,"SettingChanged");++if(!signal){+error("Unable to allocate new %s.SettingChanged signal",+interface);+returnFALSE;+}++dbus_message_iter_init_append(signal,&iter);++dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&name);++append_variant(&iter,type,value);++returng_dbus_send_message(conn,signal);+}+staticintavrcp_handle_get_capabilities(structcontrol*control,structavrcp_spec_avc_pdu*pdu){
From: Lucas De Marchi <hidden> Date: 2011-08-05 18:15:21
AVRCP_GET_PLAYER_ATTRIBUTE_TEXT and AVRCP_GET_PLAYER_VALUE_TEXT shall
only be used if TG has extended attributes.
For the ones defined in AVRCP spec these commands should not be called.
Since we do not have extended attributes yet we can ignore those
commands.
---
audio/control.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
@@ -292,6 +299,8 @@ struct control {gbooleantarget;uint8_tkey_quirks[256];++uint16_tregistered_events;};staticstruct{
@@ -1085,6 +1094,58 @@ static int avrcp_handle_get_play_status(struct control *control,return9;}+staticintavrcp_handle_register_notification(structcontrol*control,+structavrcp_spec_avc_pdu*pdu)+{+uint16_tlen=ntohs(pdu->params_len);+uint8_tstatus;++/*+*1byteforEventID,4bytesforPlaybackintervalbutthelatest+*oneisapplicableonlyforEVENT_PLAYBACK_POS_CHANGED.SeeAVRCP+*1.3spec,section5.4.2.+*/+if(len!=5)+gotoerr;++switch(pdu->params[0]){+case(AVRCP_EVENT_PLAYBACK_STATUS_CHANGED):+len=2;+if(control->mp){+mp_get_playback_status(control->mp,&status,+NULL,NULL);+pdu->params[1]=status;+}else{+pdu->params[1]=PLAY_STATUS_ERROR;+}++break;+case(AVRCP_EVENT_TRACK_CHANGED):+len=9;++if(!control->mp)+memset(&pdu->params[1],0xFF,8);+else+memset(&pdu->params[1],0,8);++break;+default:+/* All other events are not supported yet */+gotoerr;+}++/* Register event */+control->registered_events|=(1<<pdu->params[0]);++pdu->params_len=htons(len);++returnlen;++err:+pdu->params[0]=E_INVALID_PARAM;+return-EINVAL;+}+/* handle vendordep pdu inside an avctp packet */staticinthandle_vendordep_pdu(structcontrol*control,structavrcp_header*avrcp,
@@ -1238,6 +1299,19 @@ static int handle_vendordep_pdu(struct control *control,avrcp->code=CTYPE_STABLE;break;+caseAVRCP_REGISTER_NOTIFICATION:+if(avrcp->code!=CTYPE_NOTIFY){+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++len=avrcp_handle_register_notification(control,pdu);+if(len<0)+gotoerr_metadata;++avrcp->code=CTYPE_INTERIM;++break;default:/* Invalid pdu_id */pdu->params[0]=E_INVALID_COMMAND;
@@ -854,6 +855,13 @@ static int avrcp_handle_get_capabilities(struct control *control,pdu->params[1]=G_N_ELEMENTS(company_ids);return2+(3*G_N_ELEMENTS(company_ids));+caseCAP_EVENTS_SUPPORTED:+pdu->params_len=htons(4);+pdu->params[1]=2;+pdu->params[2]=AVRCP_EVENT_PLAYBACK_STATUS_CHANGED;+pdu->params[3]=AVRCP_EVENT_TRACK_CHANGED;++return4;}err:
@@ -744,6 +755,103 @@ static void mp_set_playback_status(struct control *control, uint8_t status,mp->status=status;}+/*+*Copymedia_infofieldtoabuffer,intendedtobeusedinaresponseto+*GetElementAttributesmessage.+*+*Itassumesthere'senoughspaceinthebufferandonsuccessitreturnsthe+*sizewritten.+*+*If@paramidisnotvalid,-EINVALisreturned.Ifthere'snosuchmedia+*attribute,-ENOENTisreturned.+*/+staticintmp_get_media_attribute(structmedia_player*mp,+uint32_tid,uint8_t*buf)+{+structmedia_info_elem{+uint32_tid;+uint16_tcharset;+uint16_tlen;+uint8_tval[];+};+conststructmedia_info*mi=&mp->mi;+structmedia_info_elem*elem=(void*)buf;+uint16_tlen;+charvalstr[20];++switch(id){+caseMEDIA_INFO_TITLE:+if(mi->title){+len=strlen(mi->title);+memcpy(elem->val,mi->title,len);+}else{+len=0;+}++break;+caseMEDIA_INFO_ARTIST:+if(mi->artist==NULL)+return-ENOENT;++len=strlen(mi->artist);+memcpy(elem->val,mi->artist,len);+break;+caseMEDIA_INFO_ALBUM:+if(mi->album==NULL)+return-ENOENT;++len=strlen(mi->album);+memcpy(elem->val,mi->album,len);+break;+caseMEDIA_INFO_GENRE:+if(mi->genre==NULL)+return-ENOENT;++len=strlen(mi->genre);+memcpy(elem->val,mi->genre,len);+break;++caseMEDIA_INFO_TRACK:+if(!mi->track)+return-ENOENT;++snprintf(valstr,20,"%u",mi->track);+len=strlen(valstr);+memcpy(elem->val,valstr,len);+break;+caseMEDIA_INFO_N_TRACKS:+if(!mi->ntracks)+return-ENOENT;++snprintf(valstr,20,"%u",mi->ntracks);+len=strlen(valstr);+memcpy(elem->val,valstr,len);+break;+caseMEDIA_INFO_CURRENT_POSITION:+if(mi->elapsed!=0xFFFFFFFF){+uint32_telapsed;++mp_get_playback_status(mp,NULL,&elapsed,NULL);++snprintf(valstr,20,"%u",elapsed);+len=strlen(valstr);+memcpy(elem->val,valstr,len);+}else{+return-ENOENT;+}++break;+default:+return-EINVAL;+}++elem->id=htonl(id);+elem->charset=htons(0x6A);/* Always use UTF-8 */+elem->len=htons(len);++returnsizeof(structmedia_info_elem)+len;+}+staticvoidmp_set_attribute(structmedia_player*mp,uint8_tattr,uint8_tval){
@@ -930,6 +1038,72 @@ err:return-EINVAL;}+staticintavrcp_handle_get_element_attributes(structcontrol*control,+structavrcp_spec_avc_pdu*pdu)+{+uint16_tlen=ntohs(pdu->params_len);+uint64_t*identifier=(void*)&pdu->params[0];+uint16_tpos;+uint8_tnattr;+intsize;+unsignedinti;++if(len<8||*identifier!=0||!control->mp)+gotoerr;++len=0;+pos=1;/* Keep track of current position in reponse */+nattr=pdu->params[8];++if(!control->mp)+gotodone;++if(!nattr){+/*+*Returnallavailableinformation,atleast+*titlemustbereturned.+*/+for(i=1;i<=MEDIA_INFO_CURRENT_POSITION;i++){+size=mp_get_media_attribute(control->mp,i,+&pdu->params[pos]);++if(size>0){+len++;+pos+=size;+}+}+}else{+uint32_tattr_ids[nattr];++/* save a copy of requested attributes */+memcpy(&attr_ids[0],&pdu->params[9],nattr*4);++for(i=0;i<nattr;i++){+uint32_tattr=ntohl(attr_ids[i]);++size=mp_get_media_attribute(control->mp,attr,+&pdu->params[pos]);++if(size>0){+len++;+pos+=size;+}+}++if(!len)+gotoerr;+}++done:+pdu->params[0]=len;+pdu->params_len=htons(pos);++returnpos;+err:+pdu->params[0]=E_INVALID_PARAM;+return-EINVAL;+}+staticintavrcp_handle_get_current_player_value(structcontrol*control,structavrcp_spec_avc_pdu*pdu){
@@ -1219,6 +1393,19 @@ static int handle_vendordep_pdu(struct control *control,avrcp->code=CTYPE_STABLE;break;+caseAVRCP_GET_ELEMENT_ATTRIBUTES:+if(avrcp->code!=CTYPE_STATUS){+pdu->params[0]=E_INVALID_COMMAND;+gotoerr_metadata;+}++len=avrcp_handle_get_element_attributes(control,pdu);+if(len<0)+gotoerr_metadata;++avrcp->code=CTYPE_STABLE;++break;caseAVRCP_GET_CURRENT_PLAYER_VALUE:if(avrcp->code!=CTYPE_STATUS){pdu->params[0]=E_INVALID_COMMAND;
@@ -1277,7 +1359,8 @@ static int avrcp_handle_get_play_status(struct control *control,}staticintavrcp_handle_register_notification(structcontrol*control,-structavrcp_spec_avc_pdu*pdu)+structavrcp_spec_avc_pdu*pdu,+uint8_ttransaction){uint16_tlen=ntohs(pdu->params_len);uint8_tstatus;
@@ -1316,8 +1399,9 @@ static int avrcp_handle_register_notification(struct control *control,gotoerr;}-/* Register event */+/* Register event and save the transaction used */control->registered_events|=(1<<pdu->params[0]);+control->transaction_events[pdu->params[0]]=transaction;pdu->params_len=htons(len);
@@ -1500,7 +1585,8 @@ static int handle_vendordep_pdu(struct control *control,gotoerr_metadata;}-len=avrcp_handle_register_notification(control,pdu);+len=avrcp_handle_register_notification(control,pdu,+avctp->transaction);if(len<0)gotoerr_metadata;
From: Lucas De Marchi <hidden> Date: 2011-08-05 18:15:32
Move methods and signal to an experimental interface named MediaPlayer
as currently implemented.
---
doc/control-api.txt | 101 +++++++++++++++++++++++++++------------------------
1 files changed, 54 insertions(+), 47 deletions(-)
@@ -45,44 +45,6 @@ Methods void Connect() Metadata or Events defined in the AVRCP+Metadata specification.- void ChangePlayback(string status, uint32 elapsed)-- The status can be "playing", "stopped", "paused",- "forward-seek", "reverse-seek" or "error". Elapsed is- the position within the track in milliseconds.-- void ChangeTrack(dict metadata)-- Called to send the mandated TrackChange event and- potential metadata information.-- Current defined metadata information are represented- with the following keys:-- Title string (mandatory)- Artist string- Album string- Genre string- NumberOfTracks uint32- TrackNumber uint32- TrackDuration uint32 (in milliseconds)-- void ChangeSetting(string setting, variant value)-- Called to transmit Application Settings, CT Status- and the like.-- Currenet defined settings are represented with the- following keys:-- Equalizer off, on- Repeat off, singletrack, alltracks, group- Shuffle off, alltracks, group- Scan off, alltracks, group- Battery normal, warning, critical, external, fullcharge- System powered, unpowered, unplugged- Volume uint8- Signals Connected() Sent when a successful AVRCP connection has been made
@@ -112,15 +74,6 @@ Signals Connected() connected device (except for Metadata defined in Bluetooth SIG AVRCP+Metadata spec).- TrackChanged(dict metadata)-- Called when Metadata is received from connected device.- May be multiple meta attribute/element pairs.-- PlaybackChanged(string status, uint32 elapsed)-- SettingChanged(string setting, variant value)- Properties uint8 SubUnitID [readonly] The three-bit Subunit ID from the connected device.
@@ -140,3 +93,57 @@ Properties uint8 SubUnitID [readonly] array{string} Capabilities [readonly] List of Capabilities provided by the connected device.+++MediaPlayer hierarchy [experimental]+=====================++Service org.bluez+Interface org.bluez.MediaPlayer+Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX++Methods void ChangePlayback(string status, uint32 elapsed)++ The status can be "playing", "stopped", "paused",+ "forward-seek", "reverse-seek" or "error". Elapsed is+ the position within the track in milliseconds.++ void ChangeTrack(dict metadata)++ Called to send the mandated TrackChange event and+ potential metadata information.++ Current defined metadata information are represented+ with the following keys:++ Title string (mandatory)+ Artist string+ Album string+ Genre string+ NumberOfTracks uint32+ TrackNumber uint32+ TrackDuration uint32 (in milliseconds)++ void ChangeSetting(string setting, variant value)++ Called to transmit Application Settings.++ Current defined settings are represented with the+ following keys:++ Equalizer off, on+ Repeat off, singletrack, alltracks, group+ Shuffle off, alltracks, group+ Scan off, alltracks, group++Signals TrackChanged(dict metadata)++ Called when Metadata is received from connected device.+ May be multiple meta attribute/element pairs.++ PlaybackChanged(string status, uint32 elapsed)++ SettingChanged(string setting, variant value)++ Called when one of the settings are changed by the+ remote device or to inform its battery status.
Not sure if this is really necessary, there several places where we do
that and we normally use __attribute__((packed)) is we still depend on
gcc extension in one way or the other.
--
Luiz Augusto von Dentz
Not sure if this is really necessary, there several places where we do
that and we normally use __attribute__((packed)) is we still depend on
gcc extension in one way or the other.
Fair enough. I just try to use C99 whenever possible.
Lucas De Marchi
From: Johan Hedberg <hidden> Date: 2011-08-08 14:02:13
Hi Lucas,
On Mon, Aug 08, 2011, Lucas De Marchi wrote:
quoted
quoted
+static int avrcp_handle_get_current_player_value(struct control *control,
+ struct avrcp_spec_avc_pdu *pdu)
+{
+ uint16_t len = ntohs(pdu->params_len);
+ struct media_player *mp = control->mp;
+
+ if (!mp)
+ goto done;
+
+ if (len > 1 && pdu->params[0] == len - 1) {
This if statement is quite long, perhaps you could do check the
opposite e.g. if (len <=1 || pdu->params[0] != len - 1) goto done;
In all other parts of the code I do like you said because it's much
cleaner. Here however I can't because of the following declaration:
quoted
quoted
+ uint8_t settings[pdu->params[0]];
It depends on the value of pdu->params[0]
Actually Luiz should have objected to that even more than to the coding
style. I don't think we use anywhere else array size initializers which
are not determinable upon compile time (I suppose this is also a very
recent C feature?). Furthermore, since these values are coming from the
remote side you're effectively allowing them to to "explode" our stack
here. So, dynamically allocating memory from the heap would be a (much)
better idea in this case (and then you can easily use the coding style
fix suggested by Luiz).
Johan
There should be possible to use dict_append_entry(src/dbus-common.h)
here, isn't it?
No, because it's not a dict (see that dict_append_entry calls
dbus_message_iter_open_container() ).
I could create a method for this in dbus-common, so it'd be useful for
others. What do you think?
Lucas De Marchi
From: Lucas De Marchi <hidden> Date: 2011-08-08 14:07:18
On Mon, Aug 8, 2011 at 11:02 AM, Johan Hedberg [off-list ref] wrote:
Hi Lucas,
On Mon, Aug 08, 2011, Lucas De Marchi wrote:
quoted
quoted
quoted
+static int avrcp_handle_get_current_player_value(struct control *control,
+ struct avrcp_spec_avc_pdu *pdu)
+{
+ uint16_t len = ntohs(pdu->params_len);
+ struct media_player *mp = control->mp;
+
+ if (!mp)
+ goto done;
+
+ if (len > 1 && pdu->params[0] == len - 1) {
This if statement is quite long, perhaps you could do check the
opposite e.g. if (len <=1 || pdu->params[0] != len - 1) goto done;
In all other parts of the code I do like you said because it's much
cleaner. Here however I can't because of the following declaration:
quoted
quoted
+ uint8_t settings[pdu->params[0]];
It depends on the value of pdu->params[0]
Actually Luiz should have objected to that even more than to the coding
style. I don't think we use anywhere else array size initializers which
are not determinable upon compile time (I suppose this is also a very
recent C feature?). Furthermore, since these values are coming from the
This is VLA and it's part of C99.
remote side you're effectively allowing them to to "explode" our stack
Well, it's a uint8_t. I considered this when using this approach.
here. So, dynamically allocating memory from the heap would be a (much)
better idea in this case (and then you can easily use the coding style
fix suggested by Luiz).
But this is ok for me. I'll do like you're saying.
Lucas De Marchi