1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.tuner.data; 18 19 import android.support.annotation.NonNull; 20 import android.text.TextUtils; 21 import android.text.format.DateUtils; 22 23 import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; 24 import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; 25 import com.android.tv.tuner.ts.SectionParser; 26 import com.android.tv.tuner.util.ConvertUtils; 27 import com.android.tv.util.StringUtils; 28 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Locale; 33 34 /** 35 * Collection of ATSC PSIP table items. 36 */ 37 public class PsipData { 38 PsipData()39 private PsipData() { 40 } 41 42 public static class PsipSection { 43 private final int mTableId; 44 private final int mTableIdExtension; 45 private final int mSectionNumber; 46 private final boolean mCurrentNextIndicator; 47 create(byte[] data)48 public static PsipSection create(byte[] data) { 49 if (data.length < 9) { 50 return null; 51 } 52 int tableId = data[0] & 0xff; 53 int tableIdExtension = (data[3] & 0xff) << 8 | (data[4] & 0xff); 54 int sectionNumber = data[6] & 0xff; 55 boolean currentNextIndicator = (data[5] & 0x01) != 0; 56 return new PsipSection(tableId, tableIdExtension, sectionNumber, currentNextIndicator); 57 } 58 PsipSection(int tableId, int tableIdExtension, int sectionNumber, boolean currentNextIndicator)59 private PsipSection(int tableId, int tableIdExtension, int sectionNumber, 60 boolean currentNextIndicator) { 61 mTableId = tableId; 62 mTableIdExtension = tableIdExtension; 63 mSectionNumber = sectionNumber; 64 mCurrentNextIndicator = currentNextIndicator; 65 } 66 getTableId()67 public int getTableId() { 68 return mTableId; 69 } 70 getTableIdExtension()71 public int getTableIdExtension() { 72 return mTableIdExtension; 73 } 74 getSectionNumber()75 public int getSectionNumber() { 76 return mSectionNumber; 77 } 78 79 // This is for indicating that the section sent is applicable. 80 // We only consider a situation where currentNextIndicator is expected to have a true value. 81 // So, we are not going to compare this variable in hashCode() and equals() methods. getCurrentNextIndicator()82 public boolean getCurrentNextIndicator() { 83 return mCurrentNextIndicator; 84 } 85 86 @Override hashCode()87 public int hashCode() { 88 int result = 17; 89 result = 31 * result + mTableId; 90 result = 31 * result + mTableIdExtension; 91 result = 31 * result + mSectionNumber; 92 return result; 93 } 94 95 @Override equals(Object obj)96 public boolean equals(Object obj) { 97 if (obj instanceof PsipSection) { 98 PsipSection another = (PsipSection) obj; 99 return mTableId == another.getTableId() 100 && mTableIdExtension == another.getTableIdExtension() 101 && mSectionNumber == another.getSectionNumber(); 102 } 103 return false; 104 } 105 } 106 107 /** 108 * {@link TvTracksInterface} for serving the audio and caption tracks. 109 */ 110 public interface TvTracksInterface { 111 /** 112 * Set the flag that tells the caption tracks have been found in this section container. 113 */ setHasCaptionTrack()114 void setHasCaptionTrack(); 115 116 /** 117 * Returns whether or not the caption tracks have been found in this section container. 118 * If true, zero caption track will be interpreted as a clearance of the caption tracks. 119 */ hasCaptionTrack()120 boolean hasCaptionTrack(); 121 122 /** 123 * Returns the audio tracks received. 124 */ getAudioTracks()125 List<AtscAudioTrack> getAudioTracks(); 126 127 /** 128 * Returns the caption tracks received. 129 */ getCaptionTracks()130 List<AtscCaptionTrack> getCaptionTracks(); 131 } 132 133 public static class MgtItem { 134 public static final int TABLE_TYPE_EIT_RANGE_START = 0x0100; 135 public static final int TABLE_TYPE_EIT_RANGE_END = 0x017f; 136 public static final int TABLE_TYPE_CHANNEL_ETT = 0x0004; 137 public static final int TABLE_TYPE_ETT_RANGE_START = 0x0200; 138 public static final int TABLE_TYPE_ETT_RANGE_END = 0x027f; 139 140 private final int mTableType; 141 private final int mTableTypePid; 142 MgtItem(int tableType, int tableTypePid)143 public MgtItem(int tableType, int tableTypePid) { 144 mTableType = tableType; 145 mTableTypePid = tableTypePid; 146 } 147 getTableType()148 public int getTableType() { 149 return mTableType; 150 } 151 getTableTypePid()152 public int getTableTypePid() { 153 return mTableTypePid; 154 } 155 } 156 157 public static class VctItem { 158 private final String mShortName; 159 private final String mLongName; 160 private final int mServiceType; 161 private final int mChannelTsid; 162 private final int mProgramNumber; 163 private final int mMajorChannelNumber; 164 private final int mMinorChannelNumber; 165 private final int mSourceId; 166 private String mDescription; 167 VctItem(String shortName, String longName, int serviceType, int channelTsid, int programNumber, int majorChannelNumber, int minorChannelNumber, int sourceId)168 public VctItem(String shortName, String longName, int serviceType, int channelTsid, 169 int programNumber, int majorChannelNumber, int minorChannelNumber, int sourceId) { 170 mShortName = shortName; 171 mLongName = longName; 172 mServiceType = serviceType; 173 mChannelTsid = channelTsid; 174 mProgramNumber = programNumber; 175 mMajorChannelNumber = majorChannelNumber; 176 mMinorChannelNumber = minorChannelNumber; 177 mSourceId = sourceId; 178 } 179 getShortName()180 public String getShortName() { 181 return mShortName; 182 } 183 getLongName()184 public String getLongName() { 185 return mLongName; 186 } 187 getServiceType()188 public int getServiceType() { 189 return mServiceType; 190 } 191 getChannelTsid()192 public int getChannelTsid() { 193 return mChannelTsid; 194 } 195 getProgramNumber()196 public int getProgramNumber() { 197 return mProgramNumber; 198 } 199 getMajorChannelNumber()200 public int getMajorChannelNumber() { 201 return mMajorChannelNumber; 202 } 203 getMinorChannelNumber()204 public int getMinorChannelNumber() { 205 return mMinorChannelNumber; 206 } 207 getSourceId()208 public int getSourceId() { 209 return mSourceId; 210 } 211 212 @Override toString()213 public String toString() { 214 return String 215 .format(Locale.US, "ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x " 216 + "ProgramNumber:%d %d-%d SourceId: %x", 217 mShortName, mLongName, mServiceType, mChannelTsid, 218 mProgramNumber, mMajorChannelNumber, mMinorChannelNumber, mSourceId); 219 } 220 setDescription(String description)221 public void setDescription(String description) { 222 mDescription = description; 223 } 224 getDescription()225 public String getDescription() { 226 return mDescription; 227 } 228 } 229 230 public static class SdtItem { 231 private final String mServiceName; 232 private final String mServiceProviderName; 233 private final int mServiceType; 234 private final int mServiceId; 235 private final int mOriginalNetWorkId; 236 SdtItem(String serviceName, String serviceProviderName, int serviceType, int serviceId, int originalNetWorkId)237 public SdtItem(String serviceName, String serviceProviderName, int serviceType, 238 int serviceId, int originalNetWorkId) { 239 mServiceName = serviceName; 240 mServiceProviderName = serviceProviderName; 241 mServiceType = serviceType; 242 mServiceId = serviceId; 243 mOriginalNetWorkId = originalNetWorkId; 244 } 245 getServiceName()246 public String getServiceName() { 247 return mServiceName; 248 } 249 getServiceProviderName()250 public String getServiceProviderName() { 251 return mServiceProviderName; 252 } 253 getServiceType()254 public int getServiceType() { 255 return mServiceType; 256 } 257 getServiceId()258 public int getServiceId() { 259 return mServiceId; 260 } 261 getOriginalNetworkId()262 public int getOriginalNetworkId() { 263 return mOriginalNetWorkId; 264 } 265 266 @Override toString()267 public String toString() { 268 return String.format("ServiceName: %s ServiceProviderName:%s ServiceType:%d " 269 + "OriginalNetworkId:%d", 270 mServiceName, mServiceProviderName, mServiceType, mOriginalNetWorkId); 271 } 272 } 273 274 /** 275 * A base class for descriptors of Ts packets. 276 */ 277 public abstract static class TsDescriptor { getTag()278 public abstract int getTag(); 279 } 280 281 public static class ContentAdvisoryDescriptor extends TsDescriptor { 282 private final List<RatingRegion> mRatingRegions; 283 ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions)284 public ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions) { 285 mRatingRegions = ratingRegions; 286 } 287 288 @Override getTag()289 public int getTag() { 290 return SectionParser.DESCRIPTOR_TAG_CONTENT_ADVISORY; 291 } 292 getRatingRegions()293 public List<RatingRegion> getRatingRegions() { 294 return mRatingRegions; 295 } 296 } 297 298 public static class CaptionServiceDescriptor extends TsDescriptor { 299 private final List<AtscCaptionTrack> mCaptionTracks; 300 CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks)301 public CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks) { 302 mCaptionTracks = captionTracks; 303 } 304 305 @Override getTag()306 public int getTag() { 307 return SectionParser.DESCRIPTOR_TAG_CAPTION_SERVICE; 308 } 309 getCaptionTracks()310 public List<AtscCaptionTrack> getCaptionTracks() { 311 return mCaptionTracks; 312 } 313 } 314 315 public static class ExtendedChannelNameDescriptor extends TsDescriptor { 316 private final String mLongChannelName; 317 ExtendedChannelNameDescriptor(String longChannelName)318 public ExtendedChannelNameDescriptor(String longChannelName) { 319 mLongChannelName = longChannelName; 320 } 321 322 @Override getTag()323 public int getTag() { 324 return SectionParser.DESCRIPTOR_TAG_EXTENDED_CHANNEL_NAME; 325 } 326 getLongChannelName()327 public String getLongChannelName() { 328 return mLongChannelName; 329 } 330 } 331 332 public static class GenreDescriptor extends TsDescriptor { 333 private final String[] mBroadcastGenres; 334 private final String[] mCanonicalGenres; 335 GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres)336 public GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres) { 337 mBroadcastGenres = broadcastGenres; 338 mCanonicalGenres = canonicalGenres; 339 } 340 341 @Override getTag()342 public int getTag() { 343 return SectionParser.DESCRIPTOR_TAG_GENRE; 344 } 345 getBroadcastGenres()346 public String[] getBroadcastGenres() { 347 return mBroadcastGenres; 348 } 349 getCanonicalGenres()350 public String[] getCanonicalGenres() { 351 return mCanonicalGenres; 352 } 353 } 354 355 public static class Ac3AudioDescriptor extends TsDescriptor { 356 // See A/52 Annex A. Table A4.2 357 private static final byte SAMPLE_RATE_CODE_48000HZ = 0; 358 private static final byte SAMPLE_RATE_CODE_44100HZ = 1; 359 private static final byte SAMPLE_RATE_CODE_32000HZ = 2; 360 361 private final byte mSampleRateCode; 362 private final byte mBsid; 363 private final byte mBitRateCode; 364 private final byte mSurroundMode; 365 private final byte mBsmod; 366 private final int mNumChannels; 367 private final boolean mFullSvc; 368 private final byte mLangCod; 369 private final byte mLangCod2; 370 private final byte mMainId; 371 private final byte mPriority; 372 private final byte mAsvcflags; 373 private final String mText; 374 private final String mLanguage; 375 private final String mLanguage2; 376 Ac3AudioDescriptor(byte sampleRateCode, byte bsid, byte bitRateCode, byte surroundMode, byte bsmod, int numChannels, boolean fullSvc, byte langCod, byte langCod2, byte mainId, byte priority, byte asvcflags, String text, String language, String language2)377 public Ac3AudioDescriptor(byte sampleRateCode, byte bsid, byte bitRateCode, 378 byte surroundMode, byte bsmod, int numChannels, boolean fullSvc, byte langCod, 379 byte langCod2, byte mainId, byte priority, byte asvcflags, String text, 380 String language, String language2) { 381 mSampleRateCode = sampleRateCode; 382 mBsid = bsid; 383 mBitRateCode = bitRateCode; 384 mSurroundMode = surroundMode; 385 mBsmod = bsmod; 386 mNumChannels = numChannels; 387 mFullSvc = fullSvc; 388 mLangCod = langCod; 389 mLangCod2 = langCod2; 390 mMainId = mainId; 391 mPriority = priority; 392 mAsvcflags = asvcflags; 393 mText = text; 394 mLanguage = language; 395 mLanguage2 = language2; 396 } 397 398 @Override getTag()399 public int getTag() { 400 return SectionParser.DESCRIPTOR_TAG_AC3_AUDIO_STREAM; 401 } 402 getSampleRateCode()403 public byte getSampleRateCode() { 404 return mSampleRateCode; 405 } 406 getSampleRate()407 public int getSampleRate() { 408 switch (mSampleRateCode) { 409 case SAMPLE_RATE_CODE_48000HZ: 410 return 48000; 411 case SAMPLE_RATE_CODE_44100HZ: 412 return 44100; 413 case SAMPLE_RATE_CODE_32000HZ: 414 return 32000; 415 default: 416 return 0; 417 } 418 } 419 getBsid()420 public byte getBsid() { 421 return mBsid; 422 } 423 getBitRateCode()424 public byte getBitRateCode() { 425 return mBitRateCode; 426 } 427 getSurroundMode()428 public byte getSurroundMode() { 429 return mSurroundMode; 430 } 431 getBsmod()432 public byte getBsmod() { 433 return mBsmod; 434 } 435 getNumChannels()436 public int getNumChannels() { 437 return mNumChannels; 438 } 439 isFullSvc()440 public boolean isFullSvc() { 441 return mFullSvc; 442 } 443 getLangCod()444 public byte getLangCod() { 445 return mLangCod; 446 } 447 getLangCod2()448 public byte getLangCod2() { 449 return mLangCod2; 450 } 451 getMainId()452 public byte getMainId() { 453 return mMainId; 454 } 455 getPriority()456 public byte getPriority() { 457 return mPriority; 458 } 459 getAsvcflags()460 public byte getAsvcflags() { 461 return mAsvcflags; 462 } 463 getText()464 public String getText() { 465 return mText; 466 } 467 getLanguage()468 public String getLanguage() { 469 return mLanguage; 470 } 471 getLanguage2()472 public String getLanguage2() { 473 return mLanguage2; 474 } 475 476 @Override toString()477 public String toString() { 478 return String.format(Locale.US, 479 "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, " 480 + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, " 481 + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s" 482 + ", language2: %s", mSampleRateCode, mBsid, mBitRateCode, mSurroundMode, 483 mBsmod, mNumChannels, mFullSvc, mLangCod, mLangCod2, mMainId, mPriority, 484 mAsvcflags, mText, mLanguage, mLanguage2); 485 } 486 } 487 488 public static class Iso639LanguageDescriptor extends TsDescriptor { 489 private final List<AtscAudioTrack> mAudioTracks; 490 Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks)491 public Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks) { 492 mAudioTracks = audioTracks; 493 } 494 495 @Override getTag()496 public int getTag() { 497 return SectionParser.DESCRIPTOR_TAG_ISO639LANGUAGE; 498 } 499 getAudioTracks()500 public List<AtscAudioTrack> getAudioTracks() { 501 return mAudioTracks; 502 } 503 504 @Override toString()505 public String toString() { 506 return String.format("%s %s", getClass().getName(), mAudioTracks); 507 } 508 } 509 510 public static class ServiceDescriptor extends TsDescriptor { 511 private final int mServiceType; 512 private final String mServiceProviderName; 513 private final String mServiceName; 514 ServiceDescriptor(int serviceType, String serviceProviderName, String serviceName)515 public ServiceDescriptor(int serviceType, String serviceProviderName, String serviceName) { 516 mServiceType = serviceType; 517 mServiceProviderName = serviceProviderName; 518 mServiceName = serviceName; 519 } 520 521 @Override getTag()522 public int getTag() { 523 return SectionParser.DVB_DESCRIPTOR_TAG_SERVICE; 524 } 525 getServiceType()526 public int getServiceType() { 527 return mServiceType; 528 } 529 getServiceProviderName()530 public String getServiceProviderName() { 531 return mServiceProviderName; 532 } 533 getServiceName()534 public String getServiceName() { 535 return mServiceName; 536 } 537 538 @Override toString()539 public String toString() { 540 return String.format( 541 "Service descriptor, service type: %d, " 542 + "service provider name: %s, " 543 + "service name: %s", mServiceType, mServiceProviderName, mServiceName); 544 } 545 } 546 547 public static class ShortEventDescriptor extends TsDescriptor { 548 private final String mLanguage; 549 private final String mEventName; 550 private final String mText; 551 ShortEventDescriptor(String language, String eventName, String text)552 public ShortEventDescriptor(String language, String eventName, String text) { 553 mLanguage = language; 554 mEventName = eventName; 555 mText = text; 556 } 557 getEventName()558 public String getEventName() { 559 return mEventName; 560 } 561 562 @Override getTag()563 public int getTag() { 564 return SectionParser.DVB_DESCRIPTOR_TAG_SHORT_EVENT; 565 } 566 567 @Override toString()568 public String toString() { 569 return String.format("ShortEvent Descriptor, language:%s, event name: %s, " 570 + "text:%s", mLanguage, mEventName, mText); 571 } 572 } 573 574 public static class ParentalRatingDescriptor extends TsDescriptor { 575 private final HashMap<String, Integer> mRatings; 576 ParentalRatingDescriptor(HashMap<String, Integer> ratings)577 public ParentalRatingDescriptor(HashMap<String, Integer> ratings) { 578 mRatings = ratings; 579 } 580 581 @Override getTag()582 public int getTag() { 583 return SectionParser.DVB_DESCRIPTOR_TAG_PARENTAL_RATING; 584 } 585 getRatings()586 public HashMap<String, Integer> getRatings() { 587 return mRatings; 588 } 589 590 @Override toString()591 public String toString() { 592 return String.format("Parental rating descriptor, ratings:" + mRatings); 593 } 594 } 595 596 public static class RatingRegion { 597 private final int mName; 598 private final String mDescription; 599 private final List<RegionalRating> mRegionalRatings; 600 RatingRegion(int name, String description, List<RegionalRating> regionalRatings)601 public RatingRegion(int name, String description, List<RegionalRating> regionalRatings) { 602 mName = name; 603 mDescription = description; 604 mRegionalRatings = regionalRatings; 605 } 606 getName()607 public int getName() { 608 return mName; 609 } 610 getDescription()611 public String getDescription() { 612 return mDescription; 613 } 614 getRegionalRatings()615 public List<RegionalRating> getRegionalRatings() { 616 return mRegionalRatings; 617 } 618 } 619 620 public static class RegionalRating { 621 private final int mDimension; 622 private final int mRating; 623 RegionalRating(int dimension, int rating)624 public RegionalRating(int dimension, int rating) { 625 mDimension = dimension; 626 mRating = rating; 627 } 628 getDimension()629 public int getDimension() { 630 return mDimension; 631 } 632 getRating()633 public int getRating() { 634 return mRating; 635 } 636 } 637 638 public static class EitItem implements Comparable<EitItem>, TvTracksInterface { 639 public static final long INVALID_PROGRAM_ID = -1; 640 641 // A program id is a primary key of TvContract.Programs table. So it must be positive. 642 private final long mProgramId; 643 private final int mEventId; 644 private final String mTitleText; 645 private String mDescription; 646 private final long mStartTime; 647 private final int mLengthInSecond; 648 private final String mContentRating; 649 private final List<AtscAudioTrack> mAudioTracks; 650 private final List<AtscCaptionTrack> mCaptionTracks; 651 private boolean mHasCaptionTrack; 652 private final String mBroadcastGenre; 653 private final String mCanonicalGenre; 654 EitItem(long programId, int eventId, String titleText, long startTime, int lengthInSecond, String contentRating, List<AtscAudioTrack> audioTracks, List<AtscCaptionTrack> captionTracks, String broadcastGenre, String canonicalGenre, String description)655 public EitItem(long programId, int eventId, String titleText, long startTime, 656 int lengthInSecond, String contentRating, List<AtscAudioTrack> audioTracks, 657 List<AtscCaptionTrack> captionTracks, String broadcastGenre, String canonicalGenre, 658 String description) { 659 mProgramId = programId; 660 mEventId = eventId; 661 mTitleText = titleText; 662 mStartTime = startTime; 663 mLengthInSecond = lengthInSecond; 664 mContentRating = contentRating; 665 mAudioTracks = audioTracks; 666 mCaptionTracks = captionTracks; 667 mBroadcastGenre = broadcastGenre; 668 mCanonicalGenre = canonicalGenre; 669 mDescription = description; 670 } 671 getProgramId()672 public long getProgramId() { 673 return mProgramId; 674 } 675 getEventId()676 public int getEventId() { 677 return mEventId; 678 } 679 getTitleText()680 public String getTitleText() { 681 return mTitleText; 682 } 683 setDescription(String description)684 public void setDescription(String description) { 685 mDescription = description; 686 } 687 getDescription()688 public String getDescription() { 689 return mDescription; 690 } 691 getStartTime()692 public long getStartTime() { 693 return mStartTime; 694 } 695 getLengthInSecond()696 public int getLengthInSecond() { 697 return mLengthInSecond; 698 } 699 getStartTimeUtcMillis()700 public long getStartTimeUtcMillis() { 701 return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime) * DateUtils.SECOND_IN_MILLIS; 702 } 703 getEndTimeUtcMillis()704 public long getEndTimeUtcMillis() { 705 return ConvertUtils.convertGPSTimeToUnixEpoch( 706 mStartTime + mLengthInSecond) * DateUtils.SECOND_IN_MILLIS; 707 } 708 getContentRating()709 public String getContentRating() { 710 return mContentRating; 711 } 712 713 @Override getAudioTracks()714 public List<AtscAudioTrack> getAudioTracks() { 715 return mAudioTracks; 716 } 717 718 @Override getCaptionTracks()719 public List<AtscCaptionTrack> getCaptionTracks() { 720 return mCaptionTracks; 721 } 722 getBroadcastGenre()723 public String getBroadcastGenre() { 724 return mBroadcastGenre; 725 } 726 getCanonicalGenre()727 public String getCanonicalGenre() { 728 return mCanonicalGenre; 729 } 730 731 @Override setHasCaptionTrack()732 public void setHasCaptionTrack() { 733 mHasCaptionTrack = true; 734 } 735 736 @Override hasCaptionTrack()737 public boolean hasCaptionTrack() { 738 return mHasCaptionTrack; 739 } 740 741 @Override compareTo(@onNull EitItem item)742 public int compareTo(@NonNull EitItem item) { 743 // The list of caption tracks and the program ids are not compared in here because the 744 // channels in TIF have the concept of the caption and audio tracks while the programs 745 // do not and the programs in TIF only have a program id since they are the rows of 746 // Content Provider. 747 int ret = mEventId - item.getEventId(); 748 if (ret != 0) { 749 return ret; 750 } 751 ret = StringUtils.compare(mTitleText, item.getTitleText()); 752 if (ret != 0) { 753 return ret; 754 } 755 if (mStartTime > item.getStartTime()) { 756 return 1; 757 } else if (mStartTime < item.getStartTime()) { 758 return -1; 759 } 760 if (mLengthInSecond > item.getLengthInSecond()) { 761 return 1; 762 } else if (mLengthInSecond < item.getLengthInSecond()) { 763 return -1; 764 } 765 766 // Compares content ratings 767 ret = StringUtils.compare(mContentRating, item.getContentRating()); 768 if (ret != 0) { 769 return ret; 770 } 771 772 // Compares broadcast genres 773 ret = StringUtils.compare(mBroadcastGenre, item.getBroadcastGenre()); 774 if (ret != 0) { 775 return ret; 776 } 777 // Compares canonical genres 778 ret = StringUtils.compare(mCanonicalGenre, item.getCanonicalGenre()); 779 if (ret != 0) { 780 return ret; 781 } 782 783 // Compares descriptions 784 return StringUtils.compare(mDescription, item.getDescription()); 785 } 786 getAudioLanguage()787 public String getAudioLanguage() { 788 if (mAudioTracks == null) { 789 return ""; 790 } 791 ArrayList<String> languages = new ArrayList<>(); 792 for (AtscAudioTrack audioTrack : mAudioTracks) { 793 languages.add(audioTrack.language); 794 } 795 return TextUtils.join(",", languages); 796 } 797 798 @Override toString()799 public String toString() { 800 return String.format(Locale.US, 801 "EitItem programId: %d, eventId: %d, title: %s, startTime: %10d, " 802 + "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, " 803 + "genres (broadcast: %s, canonical: %s), description: %s", 804 mProgramId, mEventId, mTitleText, mStartTime, mLengthInSecond, mContentRating, 805 mAudioTracks != null ? mAudioTracks.size() : 0, 806 mCaptionTracks != null ? mCaptionTracks.size() : 0, 807 mBroadcastGenre, mCanonicalGenre, mDescription); 808 } 809 } 810 811 public static class EttItem { 812 public final int eventId; 813 public final String text; 814 EttItem(int eventId, String text)815 public EttItem(int eventId, String text) { 816 this.eventId = eventId; 817 this.text = text; 818 } 819 } 820 } 821