2014-01-18 55 views
6

我正在開發iOS應用程序,它將與iOS 6/7兼容並從網站流式傳輸音頻.mp3文件。iOS音頻流僅適用於**某些**藍牙設備?

已經獲得這樣的使用下面的代碼工作:

-(NSString*)documentsFolder 
{ 
    NSString* dataPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; 
    if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) 
     [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:NULL]; 
    return dataPath; 
} 

-(NSString*)createURLFile:(NSString*)songURL 
{ 
    NSString* M3U_FILE = @"song.m3u"; 
    NSString* path = [NSString stringWithFormat:@"%@",[[self documentsFolder] stringByAppendingPathComponent:M3U_FILE]]; 
    if([[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil]) 
    { 
     NSFileHandle* outFile = [NSFileHandle fileHandleForWritingAtPath:path]; 
     if(outFile != nil) 
     { 
     NSData* buffer = [songURL dataUsingEncoding:NSUTF8StringEncoding]; 
     [outFile writeData:buffer]; 
     return path; 
     } 
    } 
    return nil; 
} 


- (void)createStreamer 
{ 
    // Remove any previous references. 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
    // Create a new player. 
    NSString* fileURL = [self createURLFile:self.aSong.songpath]; 
    self.songPlayer = [[AVPlayer alloc]initWithURL:[NSURL fileURLWithPath:fileURL]]; 
    NSAssert(self.songPlayer != nil, @"NIL AVPlayer Created!!!"); 
    // Observer for when the song ends... 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(playerItemDidReachEnd:) 
               name:AVPlayerItemDidPlayToEndTimeNotification 
               object:[self.songPlayer currentItem]]; 
    [[UIApplication sharedApplication] setIdleTimerDisabled: YES]; 
} 

我存儲在本地m3u格式文件.MP3文件的URL並用它來加載了AVPlayer。在iOS的早期版本中,我被告知AVPlayer會先加載歌曲然後播放,而不是立即流式傳輸。雖然這在iOS 6/7中看起來並不真實(歌曲幾乎立即開始流式傳輸),但是.m3u文件是在而不是產生任何問題的情況下創建的。

有了這個,一個迴路正在監測AVPlayer的狀態,幾秒鐘後,音頻開始播放電話,沒有問題。

出於測試目的,我成立了這起歌頁面上的MPVolumeView:

MPVolumeView *volumeView = [[[MPVolumeView alloc] initWithFrame:CGRectMake(0, 0, 310, 20)] autorelease]; 
volumeView.center = CGPointMake(160,62); 
[volumeView sizeToFit]; 
[self.view addSubview:volumeView]; 

這樣做的原因是,音量滑塊還會顯示一個指標,如果藍牙連接作爲音頻輸出來源,並允許我更改手機和藍牙設備之間的音頻路由。到現在爲止還挺好。

我通過藍牙將手機連接到我的Jawbox Jambone,在歌曲上啓動AVPlayer,並按照預期從Jawbox發出歌曲。音量控制有一個小的「帶箭頭的矩形」,表示我可以切換音頻輸出,而且當歌曲播放時,我可以在手機和Jawbox之間切換。幸福。

當我嘗試將它連接到汽車時出現問題。我有兩個經驗:

  1. 該車已經與撥打/接聽電話的電話配對。當我進入汽車時,手機甚至表示它已經配對。但是當我使用相同的代碼播放相同的音頻文件時,它們只能從手機中發出。音量滑塊根本不顯示「藍牙路由」指示器(例如,它不會將汽車識別爲音頻輸出路由)。
  2. 在另一輛車中,音頻是從另一個應用程序(某些無線電流應用程序)流式傳輸的。另一個應用程序已停止,並開始了這一個。音頻開始播放上面測試過的同一首歌曲,但在一兩秒鐘後停止播放。同樣,此時藍牙連接的音量滑塊上沒有指示符。

有人可以向我解釋爲什麼音頻可以流出到一個藍牙設備而不是另一個?

我在配置文件中遺漏了什麼(權利?),可以讓它通過藍牙將音頻流式傳輸到汽車上?

回答

0

我敢肯定MPVolumeView只能解決其符合新的低功耗藍牙規格...(藍牙低能量或BLE)藍牙設備...

我知道手機的應用不使用MPVolumeView,可能這個其他音頻播放器也不..你可能需要看看CoreBluetooth並實現你自己:(好運。github上可能有解決方案

3

在GIT有this項目。 Play iOS項目是一款適用於Play的流媒體客戶端,可在iPhone/iPad上運行。它支持背景音頻以及背景時的媒體鍵。 它支持:

  • 流Shoutcast的流
  • 顯示當前播放的曲目
  • 背景音頻
  • 鎖屏的專輯封面&播放控制
  • 的AirPlay流媒體(帶藍牙一起)。支持發送元數據 和專輯封面

您可以下載項目here。 雖然我沒有在CAR藍牙音頻播放器上測試過。希望它對你有任何幫助。

+0

我會檢查這一個出來......謝謝。 – FuzzyBunnySlippers

0

設計成揚聲器的藍牙揚聲器不成問題。

但是,汽車通常是一個「電話」藍牙揚聲器,只會接受「電話」類型的通信。

我的猜測是,您將不得不通過設置「手機音頻」連接並將傳入的音頻傳輸轉換爲空白,並將傳出的音樂流作爲手機信號來欺騙它。

請注意,信號質量可能會降低,並且有可能無法解決此問題。

+0

我已經看到類似這樣的解決方案,總是與降級音頻的警告。我不認爲這會是一個好的解決方案......但感謝您的反饋。 – FuzzyBunnySlippers

+0

是的,但請記住,您必須處理汽車的侷限性。 大多數汽車都會通過汽車揚聲器設置藍牙,甚至可以在通話進行時使音樂靜音,但是大多數汽車並非設計用於使用音頻信號,而是使用電話信號。 您將不得不針對已購買帶藍牙播放功能的汽車收音機的觀衆。 – Tschallacka

+1

問題在於,當他們在手機上收聽時,他們會聽到高質量的音頻。因此,通過這種方式,他們可以通過藍牙在手機上獲得「良好的音頻」,在汽車中獲得「糟糕的音頻」。當他們可以插入一個MP3播放器,並獲得良好的音頻(可能來自他們的iPhone)。所以如果我不得不在沒有藍牙音頻和壞音頻之間進行選擇,他們會將其與「良好的音頻」進行比較,我寧願它是「沒有藍牙音頻」而不是「音質不好」的投訴流。 – FuzzyBunnySlippers

2

在第一個示例中,您的車可能只是一個遠程播放器。您需要爲這樣的遠程註冊事件(考慮使用AVAudioPlayer,而不是一個AVPlayer也)

設置的AudioSession識別藍牙音頻路線:

- (BOOL)prepareAudioSession { 

    // deactivate existing session 
NSError *setCategoryError = nil; 
NSError *activationError = nil; 

BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil]; 
if (!success) { 
    NSLog(@"deactivationError"); 
} 

    // set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth 
success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&setCategoryError]; 
if (!success) 
{ 
    NSLog(@"setCategoryError %@",setCategoryError); 
} 

    // activate audio session 
success = [[AVAudioSession sharedInstance] setActive:YES error: &activationError]; 
if (!success) { 
    NSLog(@"activationError"); 
} 

return success; 

}

您可以檢查路線:

AVAudioSessionRouteDescription *mAVASRD = audioSession.currentRoute; 
NSLog(@"the array is %@",mAVASRD.outputs); 

for (int ctr = 0; ctr < [mAVASRD.outputs count]; ctr++) 
{ 
    AVAudioSessionPortDescription *myPortDescription = [mAVASRD.outputs objectAtIndex:ctr]; 
    NSLog(@"the type is %@",myPortDescription.portType); 
    NSLog(@"the name is %@",myPortDescription.portName); 
    NSLog(@"the UID is %@",myPortDescription.UID); 
    NSLog(@"the data sources are %@",myPortDescription.dataSources); 
} 

然後初始化AVAudioPlayer並打開RemoteControlEvents(你可以使用console在你的車送戲/ p澳洲英語的/ etc)

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

然後實現像在這個堆棧溢出問題捕獲接收事件AVAudioPlayer委託方法並在代碼中做出相應的反應:

AVAudioPlayer on Lock Screen

在場景2,當您將一個應用移動到背景(無線電流應用)並啓動您的應用時,問題的可能罪魁禍首是同樣的原因 - 您的應用必須識別用於音頻的藍牙路由。

順便說一句,對於電話和Siri,iOS使用不同的藍牙通道,默認爲遙控器(這是我爲您的汽車描述的那個)。

當您設置此路線和遠程控制事件時,您也會獲得額外的副產品 - 您的應用程序將從鎖定屏幕控制。請查看Apple的技術說明,將您的應用配置爲在後臺播放,也可以在屏幕鎖定時執行以下操作:技術質量檢查文檔QA1668

最後,爲了通過藍牙路由增加集成度,看看MPNowPlayingInfoCenter--把標題藝術家的作品和其他好東西放在車載顯示屏上的鎖屏和大多數藍牙屏幕上。

+0

我也建議你研究AV要求以處理路線變化以及路線通知。你的應用會感謝你。 – thebdog