2013-08-02 13 views
7

iPhone'umda, telefon görüşmesi sırasında kulağınıza bastığınız üst hoparlörde çalmak için uygulamamda ses almaya çalışıyorum. Mümkün olduğunu biliyorum, çünkü telefon görüşmelerini taklit eden ve tam olarak bunu yapan App Store'dan ("The Heist") "musluk musluğuna" basarak oynadım.Sesi üst (telefon görüşmesi) hoparlörden çalma

online çok araştırma yaptık ama ben olasılığını da gündeme bile olan herkes bulma şaşırtıcı derecede zor anlar yaşıyorum. mesajların büyük çoğunluğu oldukça handsfree hoparlör vs üst "telefon" hoparlör yerine, (this ve this ve this gibi), prize takılı olan kulaklık vs handsfree hoparlör hakkında görünmektedir. (Bu sorunun bir kısmı, bunun için iyi bir isim içermiyor olabilir: "telefon hoparlörü", genellikle cihazın alt kısmındaki ahizesiz hoparlörü ifade eder, bu yüzden gerçekten iyi hedeflenmiş bir arama yapmak zordur). Apple'ın Audio Session Category Route Overrides'unu inceledim ama yine de (yanlışsam beni düzelt), sadece telefonun üst kısmındaki hoparlör değil, alt kısımdaki handsfree hoparlörle ilgileniyor.

Bu konuda gibi görünüyor BİR yazı bulduk: link. Hatta bir sürü kod sağlar, bu yüzden evde özgür olduğumu düşünmüştüm, ama şimdi kodun işe yaramayacağını düşünüyorum. Kolaylık olması açısından Sadece işe yarayıp yaramayacağını görmek benim viewDidLoad içine (Anladığım eğer doğru üst hoparlöre ses yeniden yönlendirmek biri olmalıdır) DisableSpeakerPhone yöntemi kopyalanamaz, ancak ilk "assert" satırı başarısız olur ve ses altını oynatmaya devam ediyor. (Ben de yorumlarda önerildiği gibi AudioToolbox Framework'ü de içe aktardım, bu yüzden sorun değil.)

Çalıştığım kodun ana bloğu burada (test etmek için viewDidLoad benim kopyalandığım şey budur) makalesinde birkaç yöntem vardır rağmen), ben bağlantılı etmek: can kimse ya A) veya, bu kod çalışmıyor bana neden anlamaya yardımcı B:

void DisableSpeakerPhone() { 
    UInt32 dataSize = sizeof(CFStringRef); 
    CFStringRef currentRoute = NULL; 
    OSStatus result = noErr; 

    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &dataSize, &currentRoute); 

    // Set the category to use the speakers and microphone. 
    UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord; 
    result = AudioSessionSetProperty (
             kAudioSessionProperty_AudioCategory, 
             sizeof (sessionCategory), 
             &sessionCategory 
            ); 
    assert(result == kAudioSessionNoError); 

    Float64 sampleRate = 44100.0; 
    dataSize = sizeof(sampleRate); 
    result = AudioSessionSetProperty (
             kAudioSessionProperty_PreferredHardwareSampleRate, 
             dataSize, 
             &sampleRate 
            ); 
    assert(result == kAudioSessionNoError); 

    // Default to speakerphone if a headset isn't plugged in. 
    // Overriding the output audio route 

    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None; 
    dataSize = sizeof(audioRouteOverride); 
    AudioSessionSetProperty(
          kAudioSessionProperty_OverrideAudioRoute, 
          dataSize, 
          &audioRouteOverride); 

    assert(result == kAudioSessionNoError); 

    AudioSessionSetActive(YES); 
} 

benim soru şudur) bir düğmeye basmak ve sesi üst hoparlöre yönlendirmek için daha iyi bir öneri sunacak mı?

PS daha ve iOS programlama daha aşina alıyorum ama bu AudioSessions ve bu tür, ayrıntıları ve kod örnekleri çok takdir böylece dünyasına ilk baskını olduğunu! Yardımın için teşekkürler!

GÜNCELLEME: "O Was" önerisi itibaren

(aşağıda) yukarıda alıntılanan kodu çıkarılıp değiştirdik: viewDidLoad başında

[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:nil]; 
[[AVAudioSession sharedInstance] setActive: YES error:nil]; 

. Yine de çalışmıyor, (ki bununla ilgili olarak, sesin hala üstte alıcı yerine telefonun alt kısmındaki hoparlörden çıktığı anlamına geliyor). Görünüşe göre varsayılan davranış, alıcının sesini kendi başına göndermesi için AVAudioSessionCategoryPlayAndRecord olmalıdır, bu yüzden bir şeyler hala yanlıştır.

Daha spesifik ne iPod müzik çalar üzerinden ses oynuyor bu kodla yapıyorum (başlatıldı sağ Ne değer için yukarıdaki AVAudioSession hatları viewDidLoad yılında, sonra):

_musicPlayer = [MPMusicPlayerController iPodMusicPlayer]; 

ve medya için iPod Müzik Çalar bir MPMediaPickerController içinden seçilmesi:

- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection { 
    if (mediaItemCollection) { 
     [_musicPlayer setQueueWithItemCollection: mediaItemCollection]; 
     [_musicPlayer play]; 
    } 

    [self dismissViewControllerAnimated:YES completion:nil]; 
} 

bunlar bana oldukça basittir görünüyor, ben hiçbir hata veya uyarılar var ve ben Medya Seçici ve Müzik Çalar doğru çalıştığını biliyoruz becaus Doğru şarkılar çalmaya başlar, sadece yanlış konuşmacıdan çıkar. "Bu AudioSession'ı kullanarak medya oynat" yöntemi veya başka bir şey olabilir mi? Ya da herhangi bir şeyin geri değiştirilip değiştirilemeyeceğini doğrulamak için hangi ses oturum kategorisinin aktif olduğunu kontrol etmenin bir yolu var mı? Bunu yapmak için varsayılan değere güvenmek yerine, kodu alıcıyı KULLANIMI için kesin olarak söylemenin bir yolu var mı? Bir yardında gibiyim ... Ben sadece bu son bit geçmeleri için gereken, hissetmek

DÜZENLEME: Ben sadece bir teori düşünce, bu kokan iPod müzik çalar hakkında bir şey burada Alıcıdan dışarı oynamak istiyorum. Benim mantığım: resmi iPod uygulaması ile oynamaya başlamak için bir şarkı ayarlamak ve sonra geliştirdiğim uygulama üzerinden sorunsuz bir şekilde ayarlamak (duraklatmak, atlamak, vb) mümkündür. Bir uygulamadan diğerine sürekli çalma, belki de iPod Müzik Çalar'ın kendi ses yolu ayarlarına sahip olduğunu düşündü, yoksa belki de yeni uygulamada ayarları kontrol etmek için durmuyor mu? Ne hakkında konuştuklarını bilen biri bunun böyle bir şey olabileceğini düşünüyor mu?

+0

çalıştı sadece iddia nuking ve ne olur görme? – Undo

+0

Onlara her şeyi açıklayın, ve orada hiç kod yok gibidir: ses, alt hoparlörden geçer. Sanırım, iddiaların başarısız olmasına neden olan aynı sorun yüzünden, bunun ne olabileceğini bilecek kadar tecrübeli değilim. – Nerrolken

+1

Ben de değilim ... İyi şanslar! – Undo

cevap

4

Önce ses oturumunuzu başlatmanız gerekir. Bunun yerine AVAudioSession yöntemlerini kullanabilirsiniz iOS6 yılında C API

AudioSessionInitialize (NULL, NULL, NULL, NULL); 

kullanma

(AVAudioSession kullanmak size AVFoundation çerçeve ithal etmek gerekiyor):

Başlatma

self.audioSession = [AVAudioSession sharedInstance]; 
AVAudioSession

kullanarak

AudioSession kategorisini AVAudioSession

kullanarak ayarlama

const CFStringRef kAudioSessionOutputRoute_BuiltInReceiver; 
const CFStringRef kAudioSessionOutputRoute_BuiltInSpeaker; 

bkz elma docs here

Fakat asıl gizem sebebini şudur: daha iyi arama terimleri istiyorsanız daha fazla araştırma için

[self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord 
             error:nil]; 

, burada hoparlörler için sabitler tam adlarını vardır alıcıya yönlendirme konusunda herhangi bir sorun yaşıyor. PlayAndRecord kategorisi için varsayılan davranış budur. kAudioSessionOverrideAudioRoute_None Apple'ın belgeleri:

"belirtir, kAudioSessionCategory_PlayAndRecord kategori için, bu çıkış ses alıcısı gitmeli Bu, bu kategori için varsayılan çıkış ses yoldur.."

güncelleme

Güncelleştirdiğiniz soruda, MPMusicPlayerController sınıfını kullandığınızı ortaya çıkarmış olursunuz.Bu sınıf, küresel müzik çaları (Müzik uygulamasında kullanılan aynı oyuncu) çağırır. Bu müzik çalar uygulamanızdan ayrıdır ve bu nedenle uygulamanızın audioSession'ı ile aynı ses oturumunu paylaşmaz. Uygulamanızın audioSession'ında belirlediğiniz tüm özellikler, MPMusicPlayerController tarafından yoksayılacaktır.

Uygulamanızın ses davranışını kontrol etmek istiyorsanız, uygulamanızda dahili bir ses çerçevesi kullanmanız gerekir. Bu, AVAudioRecorder/AVAudioPlayer veya Çekirdek Ses (Ses Kuyrukları, Ses Birimleri veya OpenAL) olacaktır. Hangi yöntemi kullanırsanız kullanın, ses oturumu ya AVAudioSession özellikleriyle veya Çekirdek Ses API'sı aracılığıyla kontrol edilebilir. Çekirdek Ses size daha iyi bir kontrol sağlar, ancak her yeni sürümü iOS ile AVFoundation'a aktarılır. Ses oturumunun, toplam iOS ortamına göre uygulamanızın sesinin amaçlanan davranışını tanımlamanız için bir yol sağladığını, ancak tam olarak kontrol etmeyeceğinizi unutmayın. Apple, kullanıcının cihazının ses davranışlarına ilişkin beklentilerinin uygulamalar arasında tutarlı kalmasını ve bir uygulamanın başka bir ses akışını kesintiye uğratması gerektiğinde emin olmaya özen gösterir. Düzenlemenizle olarak

güncelleme 2

diğer app ses oturum ayarlarını kontrol ses oturumları olasılığı ima. Bu, gerçekleşmez. Fikir, her uygulamanın kendi kendine yeten ses oturumunu kullanarak kendi ses davranışları için tercihlerini belirlemesidir. işletim sistemi, birden fazla uygulamanın dahili mikrofon veya konuşmacılardan biri gibi paylaşılamayan bir kaynak için rekabet ettiği ve genellikle kullanıcının beklentilerini karşılaması muhtemel olan bu davranıştan yana karar verdiğinde çakışan ses gereksinimleri arasında kararlıdır. Bir bütün olarak cihazın.

MPMusicPlayerController sınıfı, bir uygulamanın diğeri üzerinde bir dereceye kadar kontrole sahip olma yeteneği vermesi açısından biraz gariptir. Bu durumda, uygulamanız ses çalmıyor, Müzik Çalar'a sizin adınıza ses çalması için bir istek gönderiyor. Kontrolünüz MPMusicPlayerController API'sinin kapsamı ile sınırlıdır. Daha fazla kontrol için uygulamanızın ses oynatmanın kendi uygulamasını sağlaması gerekir. Yorumunuza olarak

merak: Yeni soru için (büyük) bir konu

Could there be a way to pull an MPMediaItem from the MPMusicPlayerController and then play them through the app-specific audio session, or anything like that?

. İşte iyi bir başlangıç ​​okuması (Chris Adamson'un blogundan) From iPod Library to PCM Samples in Far Fewer Steps Than Were Previously Necessary - bu, From iphone media library to pcm samples in dozens of confounding and potentially lossy steps'un devamıdır - bu, karşılaşacağınız karmaşıklığa bir anlam vermelisiniz. Bu , iOS6'dan bu yana daha kolay olabilir, ancak bu kadar emin olmazdım!


orada iOS6 bir otherAudioPlaying salt okunur BOOL özelliktir, ancak

+0

Teşekkür ederiz! Sadece AVAudioSessionCategoryPlayAndRecord'a baktım ve tam da aradığım şey bu olabilir. Ancak, [[AVAudioSession sharedInstance] setCategory satırlarını ekledim: AVAudioSessionCategoryPlayAndRecord error: nil]; [[AVAudioSession sharedInstance] setActive: YES error: nil]; 'viewDidLoad'a gönderdiğim kodun yerine ve herhangi bir hata almıyorum ama yine de hoparlörden çalıyor. Ne yaptığım hakkında bir fikrin var mı? Bu satırlar viewDidLoad'a gitmemeli mi yoksa [self.musicPlayer play], 'line'ları veya herhangi bir şeyle bir şey yapmam mı gerekiyor? – Nerrolken

+0

@AlexanderWinn - evet viewDidLoad'a gitmeliler. Üzerinde herhangi bir özellik ayarlamadan önce sesli oturum başlatmanız gerekir. '[AVAudioSession sharedInstance]' bunu başarır. [Self.musicPlayer play] ile ilgili olarak, bu kodu orijinal sorunuzda yayınlamadınız. Belki de daha fazla kod bağlamında soruyu güncellemeniz gerekir, çünkü zaten gönderdiğiniz kodun çalışması gerekir. – foundry

+0

Güncellendi. Orada bir şey sorun olabilir mi? Ve şimdiye kadar yardımlarınız için tekrar teşekkür ederim! – Nerrolken

24

de bir süredir bu mücadele oldu hakkında bu. Belki bu daha sonra birine yardımcı olur. Ayrıca, yeni bağlantı noktalarını geçersiz kılma yöntemlerini de kullanabilirsiniz. Örnek kodunuzdaki yöntemlerin çoğu aslında kullanımdan kaldırılmıştır. Eğer alarak AudioSession sharedInstance sahip Yani eğer

,

NSError *error = nil; 
AVAudioSession *session = [AVAudioSession sharedInstance]; 
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 
[session setActive: YES error:nil]; 

seans kategori Bu değeri denetleyerek geçerli çıkışını alabilirsiniz AVAudioSessionCategoryPlayAndRecord olmak zorundadır.Eğer sadece bu hoparlör telefon ve alıcıya çıkışlarını geçiş yapmak için hızlı bir yoldur olmalıdır

if ([portType isEqualToString:@"Receiver"]) { 
     [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error]; 
} else { 
     [session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error]; 
} 

kullanarak çıktıyı geçiş göndermek istediğiniz portu bağlı

AVAudioSessionPortDescription *routePort = session.currentRoute.outputs.firstObject; 
NSString *portType = routePort.portType; 

Ve şimdi.

+1

Çalışmaları harika! Sadece oturum kategorisini değiştirmek ve çıkış ses portunu geçersiz kılmak zorunda kaldım, kolay! teşekkürler – YoGiN

+0

Bu çözümü denedim iOS 8. Bu çalışır. Sadece [session overrideOutputAudioPort: AVAudioSessionPortOverrideNone error: nil] var; eğer geçiş yapmak istemiyorsanız ve sadece kulak parçasındaki sesi çaldığınızda. – coolcool1994

+0

Lütfen buna bir göz atabilir misiniz? https://stackoverflow.com/questions/45424446/avaudiosession-playing-audio-through-earpiece-speaker – Shohrab

1

Swift 3.0 Kod

func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {  
let routePort: AVAudioSessionPortDescription? = obsession. current Route. outputs. first 
let portType: String? = routePort?.portType 
if (portType == "Receiver") { 
    try? audioSession.overrideOutputAudioPort(.speaker) 
    } 
    else { 
     try? audioSession.overrideOutputAudioPort(.none) 
    } 
+0

Lütfen buna bir göz atabilir misiniz? https://stackoverflow.com/questions/45424446/avaudiosession-playing-audio-through-earpiece-speaker – Shohrab

İlgili konular